diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig index b85f88c..238b2ed 100644 --- a/drivers/media/common/Kconfig +++ b/drivers/media/common/Kconfig @@ -22,4 +22,5 @@ config CYPRESS_FIRMWARE source "drivers/media/common/b2c2/Kconfig" source "drivers/media/common/saa7146/Kconfig" +source "drivers/media/common/saa716x/Kconfig" source "drivers/media/common/siano/Kconfig" diff --git a/drivers/media/common/Makefile b/drivers/media/common/Makefile index d208de3..b3c373d 100644 --- a/drivers/media/common/Makefile +++ b/drivers/media/common/Makefile @@ -1,4 +1,4 @@ -obj-y += b2c2/ saa7146/ siano/ +obj-y += b2c2/ saa7146/ saa716x/ siano/ obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o diff --git a/drivers/media/common/saa716x/Kconfig b/drivers/media/common/saa716x/Kconfig new file mode 100644 index 0000000..e667a58 --- /dev/null +++ b/drivers/media/common/saa716x/Kconfig @@ -0,0 +1,67 @@ +menuconfig SAA716X_SUPPORT + bool "Support for SAA716x family from NXP/Philips" + depends on PCI && I2C + help + support for saa716x + +if SAA716X_SUPPORT +config SAA716X_CORE + tristate "SAA7160/1/2 PCI Express bridge based devices" + depends on PCI && I2C + + help + Support for PCI cards based on the SAA7160/1/2 PCI Express bridge. + + Say Y if you own such a device and want to use it. + +config DVB_SAA716X_BUDGET + tristate "SAA7160/1/2 based Budget PCIe cards (DVB only)" + depends on SAA716X_CORE && DVB_CORE + select DVB_DS3000 if !DVB_FE_CUSTOMISE + select DVB_DS3103 if !DVB_FE_CUSTOMISE + select DVB_TS2022 if !DVB_FE_CUSTOMISE + + help + Support for the SAA7160/1/2 based Budget PCIe DVB cards + Currently supported devices are: + + * KNC1 Dual S2 (DVB-S, DVB-S/S2) + * Twinhan/Azurewave VP-1028 (DVB-S) + * Twinhan/Azurewave VP-3071 (DVB-T x2) + * Twinhan/Azurewave VP-6002 (DVB-S) + + Say Y if you own such a device and want to use it. + +config DVB_SAA716X_HYBRID + tristate "SAA7160/1/2 based Hybrid PCIe cards (DVB + Analog)" + depends on SAA716X_CORE && DVB_CORE + + help + Support for the SAA7160/1/2 based Hybrid PCIe DVB cards + Currently supported devices are: + + * Avermedia H-788 (DVB-T) + * Avermedia HC-82 (DVB-T) + * NXP Reference (Atlantis) (DVB-T x2) + * NXP Reference (Nemo) (DVB-T) + * Twinhan/Azurewave VP-6090 (DVB-S x2, DVB-T x2) + + Say Y if you own such a device and want to use it. + +#config DVB_SAA716X_FF +# tristate "SAA7160/1/2 based Full Fledged PCIe cards" +# depends on SAA716X_CORE && DVB_CORE +# depends on INPUT # IR +# default n + +# help +# Support for the SAA7160/1/2 based Full fledged PCIe DVB cards +# These cards do feature a hardware MPEG decoder and other +# peripherals. Also known as Premium cards. +# Currently supported devices are: + +# * Technotrend S2 6400 Dual S2 HD (DVB-S/S2 x2) + +# Say Y if you own such a device and want to use it. + +endif # SAA716X_SUPPORT diff --git a/drivers/media/common/saa716x/Makefile b/drivers/media/common/saa716x/Makefile new file mode 100644 index 0000000..c86f224 --- /dev/null +++ b/drivers/media/common/saa716x/Makefile @@ -0,0 +1,26 @@ +saa716x_core-objs := saa716x_pci.o \ + saa716x_i2c.o \ + saa716x_cgu.o \ + saa716x_msi.o \ + saa716x_dma.o \ + saa716x_vip.o \ + saa716x_aip.o \ + saa716x_phi.o \ + saa716x_boot.o \ + saa716x_fgpi.o \ + saa716x_adap.o \ + saa716x_gpio.o \ + saa716x_greg.o \ + saa716x_rom.o \ + saa716x_spi.o + +#saa716x_ff-objs := saa716x_ff_main.o \ +# saa716x_ff_cmd.o \ +# saa716x_ff_ir.o + +obj-$(CONFIG_SAA716X_CORE) += saa716x_core.o +obj-$(CONFIG_DVB_SAA716X_BUDGET) += saa716x_budget.o +obj-$(CONFIG_DVB_SAA716X_HYBRID) += saa716x_hybrid.o +#obj-$(CONFIG_DVB_SAA716X_FF) += saa716x_ff.o + +EXTRA_CFLAGS = -Idrivers/media/dvb-core/ -Idrivers/media/dvb-frontends/ -Idrivers/media/tuners/ diff --git a/drivers/media/common/saa716x/saa716x_adap.c b/drivers/media/common/saa716x/saa716x_adap.c new file mode 100644 index 0000000..6d7346c --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_adap.c @@ -0,0 +1,274 @@ +#include + +#include "dmxdev.h" +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" + +#include "saa716x_mod.h" +#include "saa716x_spi.h" +#include "saa716x_adap.h" +#include "saa716x_i2c.h" +#include "saa716x_gpio.h" +#include "saa716x_priv.h" +#include "saa716x_budget.h" + + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + + +void saa716x_dma_start(struct saa716x_dev *saa716x, u8 adapter) +{ + struct fgpi_stream_params params; + + dprintk(SAA716x_DEBUG, 1, "SAA716x Start DMA engine for Adapter:%d", adapter); + + params.bits = 8; + params.samples = 188; + params.lines = 348; + params.pitch = 188; + params.offset = 0; + params.page_tables = 0; + params.stream_type = FGPI_TRANSPORT_STREAM; + params.stream_flags = 0; + + saa716x_fgpi_start(saa716x, saa716x->config->adap_config[adapter].ts_port, ¶ms); +} + +void saa716x_dma_stop(struct saa716x_dev *saa716x, u8 adapter) +{ + dprintk(SAA716x_DEBUG, 1, "SAA716x Stop DMA engine for Adapter:%d", adapter); + + saa716x_fgpi_stop(saa716x, saa716x->config->adap_config[adapter].ts_port); +} + +static int saa716x_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + struct saa716x_adapter *saa716x_adap = dvbdmx->priv; + struct saa716x_dev *saa716x = saa716x_adap->saa716x; + + dprintk(SAA716x_DEBUG, 1, "SAA716x DVB Start feed"); + if (!dvbdmx->dmx.frontend) { + dprintk(SAA716x_DEBUG, 1, "no frontend ?"); + return -EINVAL; + } + saa716x_adap->feeds++; + dprintk(SAA716x_DEBUG, 1, "SAA716x start feed, feeds=%d", + saa716x_adap->feeds); + + if (saa716x_adap->feeds == 1) { + dprintk(SAA716x_DEBUG, 1, "SAA716x start feed & dma"); + saa716x_dma_start(saa716x, saa716x_adap->count); + } + + return saa716x_adap->feeds; +} + +static int saa716x_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) +{ + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + struct saa716x_adapter *saa716x_adap = dvbdmx->priv; + struct saa716x_dev *saa716x = saa716x_adap->saa716x; + + dprintk(SAA716x_DEBUG, 1, "SAA716x DVB Stop feed"); + if (!dvbdmx->dmx.frontend) { + dprintk(SAA716x_DEBUG, 1, "no frontend ?"); + return -EINVAL; + } + saa716x_adap->feeds--; + if (saa716x_adap->feeds == 0) { + dprintk(SAA716x_DEBUG, 1, "saa716x stop feed and dma"); + saa716x_dma_stop(saa716x, saa716x_adap->count); + } + + return 0; +} + +int saa716x_dvb_init(struct saa716x_dev *saa716x) +{ + struct saa716x_adapter *saa716x_adap = saa716x->saa716x_adap; + struct saa716x_config *config = saa716x->config; + int result, i; + + mutex_init(&saa716x->adap_lock); + + for (i = 0; i < config->adapters; i++) { + + dprintk(SAA716x_DEBUG, 1, "dvb_register_adapter"); + if (dvb_register_adapter(&saa716x_adap->dvb_adapter, + "SAA716x dvb adapter", + THIS_MODULE, + &saa716x->pdev->dev, + adapter_nr) < 0) { + + dprintk(SAA716x_ERROR, 1, "Error registering adapter"); + return -ENODEV; + } + + saa716x_adap->count = i; + + saa716x_adap->dvb_adapter.priv = saa716x_adap; + saa716x_adap->demux.dmx.capabilities = DMX_TS_FILTERING | + DMX_SECTION_FILTERING | + DMX_MEMORY_BASED_FILTERING; + + saa716x_adap->demux.priv = saa716x_adap; + saa716x_adap->demux.filternum = 256; + saa716x_adap->demux.feednum = 256; + saa716x_adap->demux.start_feed = saa716x_dvb_start_feed; + saa716x_adap->demux.stop_feed = saa716x_dvb_stop_feed; + saa716x_adap->demux.write_to_decoder = NULL; + switch (saa716x->pdev->subsystem_device) { + case TEVII_S472: { + struct saa716x_i2c *i2c = saa716x->i2c; + struct i2c_adapter *adapter = &i2c[SAA716x_I2C_BUS_B].i2c_adapter; + u8 mac[6]; + u8 b0[] = { 0, 9 }; + struct i2c_msg msg[] = { + { + .addr = 0x50, + .flags = 0, + .buf = b0, + .len = 2 + }, { + .addr = 0x50, + .flags = I2C_M_RD, + .buf = mac, + .len = 6 + } + }; + + i2c_transfer(adapter, msg, 2); + dprintk(SAA716x_INFO, 1, "TeVii S472 MAC= %pM\n", mac); + memcpy(saa716x_adap->dvb_adapter.proposed_mac, mac, 6); + } + } + + dprintk(SAA716x_DEBUG, 1, "dvb_dmx_init"); + if ((result = dvb_dmx_init(&saa716x_adap->demux)) < 0) { + dprintk(SAA716x_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result); + goto err0; + } + + saa716x_adap->dmxdev.filternum = 256; + saa716x_adap->dmxdev.demux = &saa716x_adap->demux.dmx; + saa716x_adap->dmxdev.capabilities = 0; + + dprintk(SAA716x_DEBUG, 1, "dvb_dmxdev_init"); + if ((result = dvb_dmxdev_init(&saa716x_adap->dmxdev, + &saa716x_adap->dvb_adapter)) < 0) { + + dprintk(SAA716x_ERROR, 1, "dvb_dmxdev_init failed, ERROR=%d", result); + goto err1; + } + + saa716x_adap->fe_hw.source = DMX_FRONTEND_0; + + if ((result = saa716x_adap->demux.dmx.add_frontend(&saa716x_adap->demux.dmx, + &saa716x_adap->fe_hw)) < 0) { + + dprintk(SAA716x_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result); + goto err2; + } + + saa716x_adap->fe_mem.source = DMX_MEMORY_FE; + + if ((result = saa716x_adap->demux.dmx.add_frontend(&saa716x_adap->demux.dmx, + &saa716x_adap->fe_mem)) < 0) { + dprintk(SAA716x_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result); + goto err3; + } + + if ((result = saa716x_adap->demux.dmx.connect_frontend(&saa716x_adap->demux.dmx, + &saa716x_adap->fe_hw)) < 0) { + + dprintk(SAA716x_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result); + goto err4; + } + + dvb_net_init(&saa716x_adap->dvb_adapter, &saa716x_adap->dvb_net, &saa716x_adap->demux.dmx); +// tasklet_init(&saa716x_adap->tasklet, saa716x_dma_xfer, (unsigned long) saa716x); + dprintk(SAA716x_DEBUG, 1, "Frontend Init"); + saa716x_adap->saa716x = saa716x; + + if (config->frontend_attach) { + result = config->frontend_attach(saa716x_adap, i); + if (result < 0) + dprintk(SAA716x_ERROR, 1, "SAA716x frontend attach failed"); + + if (saa716x_adap->fe == NULL) { + dprintk(SAA716x_ERROR, 1, "A frontend driver was not found for [%04x:%04x] subsystem [%04x:%04x]\n", + saa716x->pdev->vendor, + saa716x->pdev->device, + saa716x->pdev->subsystem_vendor, + saa716x->pdev->subsystem_device); + } else { + result = dvb_register_frontend(&saa716x_adap->dvb_adapter, saa716x_adap->fe); + if (result < 0) { + dprintk(SAA716x_ERROR, 1, "SAA716x register frontend failed"); + goto err6; + } + } + + } else { + dprintk(SAA716x_ERROR, 1, "Frontend attach = NULL"); + } + + saa716x_fgpi_init(saa716x, config->adap_config[i].ts_port, + config->adap_config[i].worker); + + saa716x_adap++; + } + + + return 0; + + /* Error conditions */ +err6: + dvb_frontend_detach(saa716x_adap->fe); +err4: + saa716x_adap->demux.dmx.remove_frontend(&saa716x_adap->demux.dmx, &saa716x_adap->fe_mem); +err3: + saa716x_adap->demux.dmx.remove_frontend(&saa716x_adap->demux.dmx, &saa716x_adap->fe_hw); +err2: + dvb_dmxdev_release(&saa716x_adap->dmxdev); +err1: + dvb_dmx_release(&saa716x_adap->demux); +err0: + dvb_unregister_adapter(&saa716x_adap->dvb_adapter); + + return result; +} +EXPORT_SYMBOL(saa716x_dvb_init); + +void saa716x_dvb_exit(struct saa716x_dev *saa716x) +{ + struct saa716x_adapter *saa716x_adap = saa716x->saa716x_adap; + int i; + + for (i = 0; i < saa716x->config->adapters; i++) { + + saa716x_fgpi_exit(saa716x, saa716x->config->adap_config[i].ts_port); + + if (saa716x_adap->fe) { + dvb_unregister_frontend(saa716x_adap->fe); + dvb_frontend_detach(saa716x_adap->fe); + } + +// tasklet_kill(&saa716x->tasklet); + dvb_net_release(&saa716x_adap->dvb_net); + saa716x_adap->demux.dmx.remove_frontend(&saa716x_adap->demux.dmx, &saa716x_adap->fe_mem); + saa716x_adap->demux.dmx.remove_frontend(&saa716x_adap->demux.dmx, &saa716x_adap->fe_hw); + dvb_dmxdev_release(&saa716x_adap->dmxdev); + dvb_dmx_release(&saa716x_adap->demux); + + dprintk(SAA716x_DEBUG, 1, "dvb_unregister_adapter"); + dvb_unregister_adapter(&saa716x_adap->dvb_adapter); + + saa716x_adap++; + } + + return; +} +EXPORT_SYMBOL(saa716x_dvb_exit); diff --git a/drivers/media/common/saa716x/saa716x_adap.h b/drivers/media/common/saa716x/saa716x_adap.h new file mode 100644 index 0000000..7822e36 --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_adap.h @@ -0,0 +1,9 @@ +#ifndef __SAA716x_ADAP_H +#define __SAA716x_ADAP_H + +struct saa716x_dev; + +extern int saa716x_dvb_init(struct saa716x_dev *saa716x); +extern void saa716x_dvb_exit(struct saa716x_dev *saa716x); + +#endif /* __SAA716x_ADAP_H */ diff --git a/drivers/media/common/saa716x/saa716x_aip.c b/drivers/media/common/saa716x/saa716x_aip.c new file mode 100644 index 0000000..3bdb265 --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_aip.c @@ -0,0 +1,20 @@ +#include + +#include "saa716x_mod.h" +#include "saa716x_aip_reg.h" +#include "saa716x_spi.h" +#include "saa716x_aip.h" +#include "saa716x_priv.h" + +int saa716x_aip_status(struct saa716x_dev *saa716x, u32 dev) +{ + return SAA716x_EPRD(dev, AI_CTL) == 0 ? 0 : -1; +} +EXPORT_SYMBOL_GPL(saa716x_aip_status); + +void saa716x_aip_disable(struct saa716x_dev *saa716x) +{ + SAA716x_EPWR(AI0, AI_CTL, 0x00); + SAA716x_EPWR(AI1, AI_CTL, 0x00); +} +EXPORT_SYMBOL_GPL(saa716x_aip_disable); diff --git a/drivers/media/common/saa716x/saa716x_aip.h b/drivers/media/common/saa716x/saa716x_aip.h new file mode 100644 index 0000000..36277b7 --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_aip.h @@ -0,0 +1,9 @@ +#ifndef __SAA716x_AIP_H +#define __SAA716x_AIP_H + +struct saa716x_dev; + +extern int saa716x_aip_status(struct saa716x_dev *saa716x, u32 dev); +extern void saa716x_aip_disable(struct saa716x_dev *saa716x); + +#endif /* __SAA716x_AIP_H */ diff --git a/drivers/media/common/saa716x/saa716x_aip_reg.h b/drivers/media/common/saa716x/saa716x_aip_reg.h new file mode 100644 index 0000000..3e0893a --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_aip_reg.h @@ -0,0 +1,62 @@ +#ifndef __SAA716x_AIP_REG_H +#define __SAA716x_AIP_REG_H + +/* -------------- AI Registers ---------------- */ + +#define AI_STATUS 0x000 +#define AI_BUF1_ACTIVE (0x00000001 << 4) +#define AI_OVERRUN (0x00000001 << 3) +#define AI_HBE (0x00000001 << 2) +#define AI_BUF2_FULL (0x00000001 << 1) +#define AI_BUF1_FULL (0x00000001 << 0) + +#define AI_CTL 0x004 +#define AI_RESET (0x00000001 << 31) +#define AI_CAP_ENABLE (0x00000001 << 30) +#define AI_CAP_MODE (0x00000003 << 28) +#define AI_SIGN_CONVERT (0x00000001 << 27) +#define AI_EARLYMODE (0x00000001 << 26) +#define AI_DIAGMODE (0x00000001 << 25) +#define AI_RAWMODE (0x00000001 << 24) +#define AI_OVR_INTEN (0x00000001 << 7) +#define AI_HBE_INTEN (0x00000001 << 6) +#define AI_BUF2_INTEN (0x00000001 << 5) +#define AI_BUF1_INTEN (0x00000001 << 4) +#define AI_ACK_OVR (0x00000001 << 3) +#define AI_ACK_HBE (0x00000001 << 2) +#define AI_ACK2 (0x00000001 << 1) +#define AI_ACK1 (0x00000001 << 0) + +#define AI_SERIAL 0x008 +#define AI_SER_MASTER (0x00000001 << 31) +#define AI_DATAMODE (0x00000001 << 30) +#define AI_FRAMEMODE (0x00000003 << 28) +#define AI_CLOCK_EDGE (0x00000001 << 27) +#define AI_SSPOS4 (0x00000001 << 19) +#define AI_NR_CHAN (0x00000003 << 17) +#define AI_WSDIV (0x000001ff << 8) +#define AI_SCKDIV (0x000000ff << 0) + +#define AI_FRAMING 0x00c +#define AI_VALIDPOS (0x000001ff << 22) +#define AI_LEFTPOS (0x000001ff << 13) +#define AI_RIGHTPOS (0x000001ff << 4) +#define AI_SSPOS_3_0 (0x0000000f << 0) + +#define AI_BASE1 0x014 +#define AI_BASE2 0x018 +#define AI_BASE (0x03ffffff << 6) + +#define AI_SIZE 0x01c +#define AI_SAMPLE_SIZE (0x03ffffff << 6) + +#define AI_INT_ACK 0x020 +#define AI_ACK_OVR (0x00000001 << 3) +#define AI_ACK_HBE (0x00000001 << 2) +#define AI_ACK2 (0x00000001 << 1) +#define AI_ACK1 (0x00000001 << 0) + +#define AI_PWR_DOWN 0xff4 +#define AI_PWR_DWN (0x00000001 << 0) + +#endif /* __SAA716x_AIP_REG_H */ diff --git a/drivers/media/common/saa716x/saa716x_boot.c b/drivers/media/common/saa716x/saa716x_boot.c new file mode 100644 index 0000000..21e59d0 --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_boot.c @@ -0,0 +1,319 @@ +#include + +#include "saa716x_mod.h" + +#include "saa716x_greg_reg.h" +#include "saa716x_cgu_reg.h" +#include "saa716x_vip_reg.h" +#include "saa716x_aip_reg.h" +#include "saa716x_msi_reg.h" +#include "saa716x_dma_reg.h" +#include "saa716x_gpio_reg.h" +#include "saa716x_fgpi_reg.h" +#include "saa716x_dcs_reg.h" + +#include "saa716x_boot.h" +#include "saa716x_spi.h" +#include "saa716x_priv.h" + +static int saa716x_ext_boot(struct saa716x_dev *saa716x) +{ + /* Write GREG boot_ready to 0 + * DW_0 = 0x0001_2018 + * DW_1 = 0x0000_0000 + */ + SAA716x_EPWR(GREG, GREG_RSTU_CTRL, 0x00000000); + + /* Clear VI0 interrupt + * DW_2 = 0x0000_0fe8 + * DW_3 = 0x0000_03ff + */ + SAA716x_EPWR(VI0, INT_CLR_STATUS, 0x000003ff); + + /* Clear VI1 interrupt + * DW_4 = 0x0000_1fe8 + * DW_5 = 0x0000_03ff + */ + SAA716x_EPWR(VI1, INT_CLR_STATUS, 0x000003ff); + + /* CLear FGPI0 interrupt + * DW_6 = 0x0000_2fe8 + * DW_7 = 0x0000_007f + */ + SAA716x_EPWR(FGPI0, INT_CLR_STATUS, 0x0000007f); + + /* Clear FGPI1 interrupt + * DW_8 = 0x0000_3fe8 + * DW_9 = 0x0000_007f + */ + SAA716x_EPWR(FGPI1, INT_CLR_STATUS, 0x0000007f); + + /* Clear FGPI2 interrupt + * DW_10 = 0x0000_4fe8 + * DW_11 = 0x0000_007f + */ + SAA716x_EPWR(FGPI2, INT_CLR_STATUS, 0x0000007f); + + /* Clear FGPI3 interrupt + * DW_12 = 0x0000_5fe8 + * DW_13 = 0x0000_007f + */ + SAA716x_EPWR(FGPI3, INT_CLR_STATUS, 0x0000007f); + + /* Clear AI0 interrupt + * DW_14 = 0x0000_6020 + * DW_15 = 0x0000_000f + */ + SAA716x_EPWR(AI0, AI_INT_ACK, 0x0000000f); + + /* Clear AI1 interrupt + * DW_16 = 0x0000_7020 + * DW_17 = 0x0000_200f + */ + SAA716x_EPWR(AI1, AI_INT_ACK, 0x0000000f); + + /* Set GREG boot_ready bit to 1 + * DW_18 = 0x0001_2018 + * DW_19 = 0x0000_2000 + */ + SAA716x_EPWR(GREG, GREG_RSTU_CTRL, 0x00002000); +#if 0 + /* End of Boot script command + * DW_20 = 0x0000_0006 + * Where to write this value ?? + * This seems very odd an address to trigger the + * Boot Control State Machine ! + */ + SAA716x_EPWR(VI0, 0x00000006, 0xffffffff); +#endif + return 0; +} + +/* Internal Bootscript configuration */ +static void saa716x_int_boot(struct saa716x_dev *saa716x) +{ + /* #1 Configure PCI COnfig space + * GREG_JETSTR_CONFIG_0 + */ + SAA716x_EPWR(GREG, GREG_SUBSYS_CONFIG, saa716x->pdev->subsystem_vendor); + + /* GREG_JETSTR_CONFIG_1 + * pmcsr_scale:7 = 0x00 + * pmcsr_scale:6 = 0x00 + * pmcsr_scale:5 = 0x00 + * pmcsr_scale:4 = 0x00 + * pmcsr_scale:3 = 0x00 + * pmcsr_scale:2 = 0x00 + * pmcsr_scale:1 = 0x00 + * pmcsr_scale:0 = 0x00 + * BAR mask = 20 bit + * BAR prefetch = no + * MSI capable = 32 messages + */ + SAA716x_EPWR(GREG, GREG_MSI_BAR_PMCSR, 0x00001005); + + /* GREG_JETSTR_CONFIG_2 + * pmcsr_data:3 = 0x0 + * pmcsr_data:2 = 0x0 + * pmcsr_data:1 = 0x0 + * pmcsr_data:0 = 0x0 + */ + SAA716x_EPWR(GREG, GREG_PMCSR_DATA_1, 0x00000000); + + /* GREG_JETSTR_CONFIG_3 + * pmcsr_data:7 = 0x0 + * pmcsr_data:6 = 0x0 + * pmcsr_data:5 = 0x0 + * pmcsr_data:4 = 0x0 + */ + SAA716x_EPWR(GREG, GREG_PMCSR_DATA_2, 0x00000000); + + /* #2 Release GREG resets + * ip_rst_an + * dpa1_rst_an + * jetsream_reset_an + */ + SAA716x_EPWR(GREG, GREG_RSTU_CTRL, 0x00000e00); + + /* #3 GPIO Setup + * GPIO 25:24 = Output + * GPIO Output "0" after Reset + */ + SAA716x_EPWR(GPIO, GPIO_OEN, 0xfcffffff); + + /* #4 Custom stuff goes in here */ + + /* #5 Disable CGU Clocks + * except for PHY, Jetstream, DPA1, DCS, Boot, GREG + * CGU_PCR_0_3: pss_mmu_clk:0 = 0x0 + */ + SAA716x_EPWR(CGU, CGU_PCR_0_3, 0x00000006); + + /* CGU_PCR_0_4: pss_dtl2mtl_mmu_clk:0 = 0x0 */ + SAA716x_EPWR(CGU, CGU_PCR_0_4, 0x00000006); + + /* CGU_PCR_0_5: pss_msi_ck:0 = 0x0 */ + SAA716x_EPWR(CGU, CGU_PCR_0_5, 0x00000006); + + /* CGU_PCR_0_7: pss_gpio_clk:0 = 0x0 */ + SAA716x_EPWR(CGU, CGU_PCR_0_7, 0x00000006); + + /* CGU_PCR_2_1: spi_clk:0 = 0x0 */ + SAA716x_EPWR(CGU, CGU_PCR_2_1, 0x00000006); + + /* CGU_PCR_3_2: i2c_clk:0 = 0x0 */ + SAA716x_EPWR(CGU, CGU_PCR_3_2, 0x00000006); + + /* CGU_PCR_4_1: phi_clk:0 = 0x0 */ + SAA716x_EPWR(CGU, CGU_PCR_4_1, 0x00000006); + + /* CGU_PCR_5: vip0_clk:0 = 0x0 */ + SAA716x_EPWR(CGU, CGU_PCR_5, 0x00000006); + + /* CGU_PCR_6: vip1_clk:0 = 0x0 */ + SAA716x_EPWR(CGU, CGU_PCR_6, 0x00000006); + + /* CGU_PCR_7: fgpi0_clk:0 = 0x0 */ + SAA716x_EPWR(CGU, CGU_PCR_7, 0x00000006); + + /* CGU_PCR_8: fgpi1_clk:0 = 0x0 */ + SAA716x_EPWR(CGU, CGU_PCR_8, 0x00000006); + + /* CGU_PCR_9: fgpi2_clk:0 = 0x0 */ + SAA716x_EPWR(CGU, CGU_PCR_9, 0x00000006); + + /* CGU_PCR_10: fgpi3_clk:0 = 0x0 */ + SAA716x_EPWR(CGU, CGU_PCR_10, 0x00000006); + + /* CGU_PCR_11: ai0_clk:0 = 0x0 */ + SAA716x_EPWR(CGU, CGU_PCR_11, 0x00000006); + + /* CGU_PCR_12: ai1_clk:0 = 0x0 */ + SAA716x_EPWR(CGU, CGU_PCR_12, 0x00000006); + + /* #6 Set GREG boot_ready = 0x1 */ + SAA716x_EPWR(GREG, GREG_RSTU_CTRL, 0x00002000); + + /* #7 Disable GREG CGU Clock */ + SAA716x_EPWR(CGU, CGU_PCR_0_6, 0x00000006); + + /* End of Bootscript command ?? */ +} + +int saa716x_core_boot(struct saa716x_dev *saa716x) +{ + struct saa716x_config *config = saa716x->config; + + switch (config->boot_mode) { + case SAA716x_EXT_BOOT: + dprintk(SAA716x_DEBUG, 1, "Using External Boot from config"); + saa716x_ext_boot(saa716x); + break; + case SAA716x_INT_BOOT: + dprintk(SAA716x_DEBUG, 1, "Using Internal Boot from config"); + saa716x_int_boot(saa716x); + break; + default: + dprintk(SAA716x_ERROR, 1, "Unknown configuration %d", config->boot_mode); + break; + } + + return 0; +} +EXPORT_SYMBOL_GPL(saa716x_core_boot); + +static void saa716x_bus_report(struct pci_dev *pdev, int enable) +{ + u32 reg; + + pci_read_config_dword(pdev, 0x04, ®); + if (enable) + reg |= 0x00000100; /* enable SERR */ + else + reg &= 0xfffffeff; /* disable SERR */ + pci_write_config_dword(pdev, 0x04, reg); + + pci_read_config_dword(pdev, 0x58, ®); + reg &= 0xfffffffd; + pci_write_config_dword(pdev, 0x58, reg); +} + +int saa716x_jetpack_init(struct saa716x_dev *saa716x) +{ + /* + * configure PHY through config space not to report + * non-fatal error messages to avoid problems with + * quirky BIOS'es + */ + saa716x_bus_report(saa716x->pdev, 0); + + /* + * create time out for blocks that have no clock + * helps with lower bitrates on FGPI + */ + SAA716x_EPWR(DCS, DCSC_CTRL, ENABLE_TIMEOUT); + + /* Reset all blocks */ + SAA716x_EPWR(MSI, MSI_SW_RST, MSI_SW_RESET); + SAA716x_EPWR(MMU, MMU_SW_RST, MMU_SW_RESET); + SAA716x_EPWR(BAM, BAM_SW_RST, BAM_SW_RESET); + + switch (saa716x->pdev->device) { + case SAA7162: + dprintk(SAA716x_DEBUG, 1, "SAA%02x Decoder disable", saa716x->pdev->device); + SAA716x_EPWR(GPIO, GPIO_OEN, 0xfcffffff); + SAA716x_EPWR(GPIO, GPIO_WR, 0x00000000); /* Disable decoders */ + msleep(10); + SAA716x_EPWR(GPIO, GPIO_WR, 0x03000000); /* Enable decoders */ + break; + case SAA7161: + dprintk(SAA716x_DEBUG, 1, "SAA%02x Decoder disable", saa716x->pdev->device); + SAA716x_EPWR(GPIO, GPIO_OEN, 0xfeffffff); + SAA716x_EPWR(GPIO, GPIO_WR, 0x00000000); /* Disable decoders */ + msleep(10); + SAA716x_EPWR(GPIO, GPIO_WR, 0x01000000); /* Enable decoder */ + break; + case SAA7160: + saa716x->i2c_rate = SAA716x_I2C_RATE_100; + break; + default: + dprintk(SAA716x_ERROR, 1, "Unknown device (0x%02x)", saa716x->pdev->device); + return -ENODEV; + } + + /* General setup for MMU */ + SAA716x_EPWR(MMU, MMU_MODE, 0x14); + dprintk(SAA716x_DEBUG, 1, "SAA%02x Jetpack Successfully initialized", saa716x->pdev->device); + + return 0; +} +EXPORT_SYMBOL(saa716x_jetpack_init); + +void saa716x_core_reset(struct saa716x_dev *saa716x) +{ + dprintk(SAA716x_DEBUG, 1, "RESET Modules"); + + /* VIP */ + SAA716x_EPWR(VI0, VI_MODE, SOFT_RESET); + SAA716x_EPWR(VI1, VI_MODE, SOFT_RESET); + + /* FGPI */ + SAA716x_EPWR(FGPI0, FGPI_SOFT_RESET, FGPI_SOFTWARE_RESET); + SAA716x_EPWR(FGPI1, FGPI_SOFT_RESET, FGPI_SOFTWARE_RESET); + SAA716x_EPWR(FGPI2, FGPI_SOFT_RESET, FGPI_SOFTWARE_RESET); + SAA716x_EPWR(FGPI3, FGPI_SOFT_RESET, FGPI_SOFTWARE_RESET); + + /* AIP */ + SAA716x_EPWR(AI0, AI_CTL, AI_RESET); + SAA716x_EPWR(AI1, AI_CTL, AI_RESET); + + /* BAM */ + SAA716x_EPWR(BAM, BAM_SW_RST, BAM_SW_RESET); + + /* MMU */ + SAA716x_EPWR(MMU, MMU_SW_RST, MMU_SW_RESET); + + /* MSI */ + SAA716x_EPWR(MSI, MSI_SW_RST, MSI_SW_RESET); +} +EXPORT_SYMBOL_GPL(saa716x_core_reset); diff --git a/drivers/media/common/saa716x/saa716x_boot.h b/drivers/media/common/saa716x/saa716x_boot.h new file mode 100644 index 0000000..8102853 --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_boot.h @@ -0,0 +1,18 @@ +#ifndef __SAA716x_BOOT_H +#define __SAA716x_BOOT_H + +#define DISABLE_TIMEOUT 0x17 +#define ENABLE_TIMEOUT 0x16 + +enum saa716x_boot_mode { + SAA716x_EXT_BOOT = 1, + SAA716x_INT_BOOT, /* GPIO[31:30] = 0x01 */ +}; + +struct saa716x_dev; + +extern int saa716x_core_boot(struct saa716x_dev *saa716x); +extern int saa716x_jetpack_init(struct saa716x_dev *saa716x); +extern void saa716x_core_reset(struct saa716x_dev *saa716x); + +#endif /* __SAA716x_BOOT_H */ diff --git a/drivers/media/common/saa716x/saa716x_budget.c b/drivers/media/common/saa716x/saa716x_budget.c new file mode 100644 index 0000000..6b52fc1 --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_budget.c @@ -0,0 +1,717 @@ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "saa716x_mod.h" + +#include "saa716x_gpio_reg.h" +#include "saa716x_greg_reg.h" +#include "saa716x_msi_reg.h" + +#include "saa716x_adap.h" +#include "saa716x_i2c.h" +#include "saa716x_msi.h" +#include "saa716x_budget.h" +#include "saa716x_gpio.h" +#include "saa716x_rom.h" +#include "saa716x_spi.h" +#include "saa716x_priv.h" + +#include "mb86a16.h" +#include "stv6110x.h" +#include "stv090x.h" +#include "ds3103.h" +#include "ts2022.h" + +unsigned int verbose; +module_param(verbose, int, 0644); +MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)"); + +unsigned int int_type; +module_param(int_type, int, 0644); +MODULE_PARM_DESC(int_type, "force Interrupt Handler type: 0=INT-A, 1=MSI, 2=MSI-X. default INT-A mode"); + +#define DRIVER_NAME "SAA716x Budget" + +static int saa716x_budget_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) +{ + struct saa716x_dev *saa716x; + int err = 0; + + saa716x = kzalloc(sizeof (struct saa716x_dev), GFP_KERNEL); + if (saa716x == NULL) { + printk(KERN_ERR "saa716x_budget_pci_probe ERROR: out of memory\n"); + err = -ENOMEM; + goto fail0; + } + + saa716x->verbose = verbose; + saa716x->int_type = int_type; + saa716x->pdev = pdev; + saa716x->config = (struct saa716x_config *) pci_id->driver_data; + + err = saa716x_pci_init(saa716x); + if (err) { + dprintk(SAA716x_ERROR, 1, "SAA716x PCI Initialization failed"); + goto fail1; + } + + err = saa716x_cgu_init(saa716x); + if (err) { + dprintk(SAA716x_ERROR, 1, "SAA716x CGU Init failed"); + goto fail1; + } + + err = saa716x_core_boot(saa716x); + if (err) { + dprintk(SAA716x_ERROR, 1, "SAA716x Core Boot failed"); + goto fail2; + } + dprintk(SAA716x_DEBUG, 1, "SAA716x Core Boot Success"); + + err = saa716x_msi_init(saa716x); + if (err) { + dprintk(SAA716x_ERROR, 1, "SAA716x MSI Init failed"); + goto fail2; + } + + err = saa716x_jetpack_init(saa716x); + if (err) { + dprintk(SAA716x_ERROR, 1, "SAA716x Jetpack core initialization failed"); + goto fail1; + } + + err = saa716x_i2c_init(saa716x); + if (err) { + dprintk(SAA716x_ERROR, 1, "SAA716x I2C Initialization failed"); + goto fail3; + } + + saa716x_gpio_init(saa716x); + + err = saa716x_dump_eeprom(saa716x); + if (err) { + dprintk(SAA716x_ERROR, 1, "SAA716x EEPROM dump failed"); + } + + err = saa716x_eeprom_data(saa716x); + if (err) { + dprintk(SAA716x_ERROR, 1, "SAA716x EEPROM read failed"); + } + + /* set default port mapping */ + SAA716x_EPWR(GREG, GREG_VI_CTRL, 0x04080FA9); + /* enable FGPI3 and FGPI1 for TS input from Port 2 and 6 */ + SAA716x_EPWR(GREG, GREG_FGPI_CTRL, 0x321); + + err = saa716x_dvb_init(saa716x); + if (err) { + dprintk(SAA716x_ERROR, 1, "SAA716x DVB initialization failed"); + goto fail4; + } + + return 0; + +fail4: + saa716x_dvb_exit(saa716x); +fail3: + saa716x_i2c_exit(saa716x); +fail2: + saa716x_pci_exit(saa716x); +fail1: + kfree(saa716x); +fail0: + return err; +} + +static void saa716x_budget_pci_remove(struct pci_dev *pdev) +{ + struct saa716x_dev *saa716x = pci_get_drvdata(pdev); + + saa716x_dvb_exit(saa716x); + saa716x_i2c_exit(saa716x); + saa716x_pci_exit(saa716x); + kfree(saa716x); +} + +static irqreturn_t saa716x_budget_pci_irq(int irq, void *dev_id) +{ + struct saa716x_dev *saa716x = (struct saa716x_dev *) dev_id; + + u32 stat_h, stat_l, mask_h, mask_l; + + if (unlikely(saa716x == NULL)) { + printk("%s: saa716x=NULL", __func__); + return IRQ_NONE; + } + + stat_l = SAA716x_EPRD(MSI, MSI_INT_STATUS_L); + stat_h = SAA716x_EPRD(MSI, MSI_INT_STATUS_H); + mask_l = SAA716x_EPRD(MSI, MSI_INT_ENA_L); + mask_h = SAA716x_EPRD(MSI, MSI_INT_ENA_H); + + dprintk(SAA716x_DEBUG, 1, "MSI STAT L=<%02x> H=<%02x>, CTL L=<%02x> H=<%02x>", + stat_l, stat_h, mask_l, mask_h); + + if (!((stat_l & mask_l) || (stat_h & mask_h))) + return IRQ_NONE; + + if (stat_l) + SAA716x_EPWR(MSI, MSI_INT_STATUS_CLR_L, stat_l); + + if (stat_h) + SAA716x_EPWR(MSI, MSI_INT_STATUS_CLR_H, stat_h); + + saa716x_msi_event(saa716x, stat_l, stat_h); +#if 0 + dprintk(SAA716x_DEBUG, 1, "VI STAT 0=<%02x> 1=<%02x>, CTL 1=<%02x> 2=<%02x>", + SAA716x_EPRD(VI0, INT_STATUS), + SAA716x_EPRD(VI1, INT_STATUS), + SAA716x_EPRD(VI0, INT_ENABLE), + SAA716x_EPRD(VI1, INT_ENABLE)); + + dprintk(SAA716x_DEBUG, 1, "FGPI STAT 0=<%02x> 1=<%02x>, CTL 1=<%02x> 2=<%02x>", + SAA716x_EPRD(FGPI0, INT_STATUS), + SAA716x_EPRD(FGPI1, INT_STATUS), + SAA716x_EPRD(FGPI0, INT_ENABLE), + SAA716x_EPRD(FGPI0, INT_ENABLE)); + + dprintk(SAA716x_DEBUG, 1, "FGPI STAT 2=<%02x> 3=<%02x>, CTL 2=<%02x> 3=<%02x>", + SAA716x_EPRD(FGPI2, INT_STATUS), + SAA716x_EPRD(FGPI3, INT_STATUS), + SAA716x_EPRD(FGPI2, INT_ENABLE), + SAA716x_EPRD(FGPI3, INT_ENABLE)); + + dprintk(SAA716x_DEBUG, 1, "AI STAT 0=<%02x> 1=<%02x>, CTL 0=<%02x> 1=<%02x>", + SAA716x_EPRD(AI0, AI_STATUS), + SAA716x_EPRD(AI1, AI_STATUS), + SAA716x_EPRD(AI0, AI_CTL), + SAA716x_EPRD(AI1, AI_CTL)); + + dprintk(SAA716x_DEBUG, 1, "I2C STAT 0=<%02x> 1=<%02x>, CTL 0=<%02x> 1=<%02x>", + SAA716x_EPRD(I2C_A, INT_STATUS), + SAA716x_EPRD(I2C_B, INT_STATUS), + SAA716x_EPRD(I2C_A, INT_ENABLE), + SAA716x_EPRD(I2C_B, INT_ENABLE)); + + dprintk(SAA716x_DEBUG, 1, "DCS STAT=<%02x>, CTL=<%02x>", + SAA716x_EPRD(DCS, DCSC_INT_STATUS), + SAA716x_EPRD(DCS, DCSC_INT_ENABLE)); +#endif + + if (stat_l) { + if (stat_l & MSI_INT_TAGACK_FGPI_0) { + tasklet_schedule(&saa716x->fgpi[0].tasklet); + } + if (stat_l & MSI_INT_TAGACK_FGPI_1) { + tasklet_schedule(&saa716x->fgpi[1].tasklet); + } + if (stat_l & MSI_INT_TAGACK_FGPI_2) { + tasklet_schedule(&saa716x->fgpi[2].tasklet); + } + if (stat_l & MSI_INT_TAGACK_FGPI_3) { + tasklet_schedule(&saa716x->fgpi[3].tasklet); + } + } + + return IRQ_HANDLED; +} + +static void demux_worker(unsigned long data) +{ + struct saa716x_fgpi_stream_port *fgpi_entry = (struct saa716x_fgpi_stream_port *)data; + struct saa716x_dev *saa716x = fgpi_entry->saa716x; + struct dvb_demux *demux; + u32 fgpi_index; + u32 i; + u32 write_index; + + fgpi_index = fgpi_entry->dma_channel - 6; + demux = NULL; + for (i = 0; i < saa716x->config->adapters; i++) { + if (saa716x->config->adap_config[i].ts_port == fgpi_index) { + demux = &saa716x->saa716x_adap[i].demux; + break; + } + } + if (demux == NULL) { + printk(KERN_ERR "%s: unexpected channel %u\n", + __func__, fgpi_entry->dma_channel); + return; + } + + write_index = saa716x_fgpi_get_write_index(saa716x, fgpi_index); + if (write_index < 0) + return; + + dprintk(SAA716x_DEBUG, 1, "dma buffer = %d", write_index); + + if (write_index == fgpi_entry->read_index) { + printk(KERN_DEBUG "%s: called but nothing to do\n", __func__); + return; + } + + do { + u8 *data = (u8 *)fgpi_entry->dma_buf[fgpi_entry->read_index].mem_virt; + + pci_dma_sync_sg_for_cpu(saa716x->pdev, + fgpi_entry->dma_buf[fgpi_entry->read_index].sg_list, + fgpi_entry->dma_buf[fgpi_entry->read_index].list_len, + PCI_DMA_FROMDEVICE); + + dvb_dmx_swfilter(demux, data, 348 * 188); + + fgpi_entry->read_index = (fgpi_entry->read_index + 1) & 7; + } while (write_index != fgpi_entry->read_index); +} + + +#define SAA716x_MODEL_TWINHAN_VP3071 "Twinhan/Azurewave VP-3071" +#define SAA716x_DEV_TWINHAN_VP3071 "2x DVB-T" + +static int saa716x_vp3071_frontend_attach(struct saa716x_adapter *adapter, int count) +{ + struct saa716x_dev *saa716x = adapter->saa716x; + dprintk(SAA716x_DEBUG, 1, "Adapter (%d) SAA716x frontend Init", count); + dprintk(SAA716x_DEBUG, 1, "Adapter (%d) Device ID=%02x", count, saa716x->pdev->subsystem_device); + + return -ENODEV; +} + +static struct saa716x_config saa716x_vp3071_config = { + .model_name = SAA716x_MODEL_TWINHAN_VP3071, + .dev_type = SAA716x_DEV_TWINHAN_VP3071, + .boot_mode = SAA716x_EXT_BOOT, + .adapters = 2, + .frontend_attach = saa716x_vp3071_frontend_attach, + .irq_handler = saa716x_budget_pci_irq, + .i2c_rate = SAA716x_I2C_RATE_100, +}; + + +#define SAA716x_MODEL_TWINHAN_VP1028 "Twinhan/Azurewave VP-1028" +#define SAA716x_DEV_TWINHAN_VP1028 "DVB-S" + +static int vp1028_dvbs_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +{ + struct saa716x_dev *saa716x = fe->dvb->priv; + + switch (voltage) { + case SEC_VOLTAGE_13: + dprintk(SAA716x_ERROR, 1, "Polarization=[13V]"); + break; + case SEC_VOLTAGE_18: + dprintk(SAA716x_ERROR, 1, "Polarization=[18V]"); + break; + case SEC_VOLTAGE_OFF: + dprintk(SAA716x_ERROR, 1, "Frontend (dummy) POWERDOWN"); + break; + default: + dprintk(SAA716x_ERROR, 1, "Invalid = (%d)", (u32 ) voltage); + return -EINVAL; + } + + return 0; +} + +struct mb86a16_config vp1028_mb86a16_config = { + .demod_address = 0x08, + .set_voltage = vp1028_dvbs_set_voltage, +}; + +static int saa716x_vp1028_frontend_attach(struct saa716x_adapter *adapter, int count) +{ + struct saa716x_dev *saa716x = adapter->saa716x; + struct saa716x_i2c *i2c = &saa716x->i2c[1]; + + if (count == 0) { + + mutex_lock(&saa716x->adap_lock); + + dprintk(SAA716x_DEBUG, 1, "Adapter (%d) Power ON", count); + saa716x_gpio_set_output(saa716x, 10); + msleep(1); + + /* VP-1028 has inverted power supply control */ + saa716x_gpio_write(saa716x, 10, 1); /* set to standby */ + saa716x_gpio_write(saa716x, 10, 0); /* switch it on */ + msleep(100); + + dprintk(SAA716x_DEBUG, 1, "Adapter (%d) Reset", count); + saa716x_gpio_set_output(saa716x, 12); + msleep(1); + + /* reset demodulator (Active LOW) */ + saa716x_gpio_write(saa716x, 12, 1); + msleep(100); + saa716x_gpio_write(saa716x, 12, 0); + msleep(100); + saa716x_gpio_write(saa716x, 12, 1); + msleep(100); + + mutex_unlock(&saa716x->adap_lock); + + dprintk(SAA716x_ERROR, 1, "Probing for MB86A16 (DVB-S/DSS)"); + adapter->fe = mb86a16_attach(&vp1028_mb86a16_config, &i2c->i2c_adapter); + if (adapter->fe) { + dprintk(SAA716x_ERROR, 1, "found MB86A16 DVB-S/DSS frontend @0x%02x", + vp1028_mb86a16_config.demod_address); + + } else { + goto exit; + } + dprintk(SAA716x_ERROR, 1, "Done!"); + } + + return 0; +exit: + dprintk(SAA716x_ERROR, 1, "Frontend attach failed"); + return -ENODEV; +} + +static struct saa716x_config saa716x_vp1028_config = { + .model_name = SAA716x_MODEL_TWINHAN_VP1028, + .dev_type = SAA716x_DEV_TWINHAN_VP1028, + .boot_mode = SAA716x_EXT_BOOT, + .adapters = 1, + .frontend_attach = saa716x_vp1028_frontend_attach, + .irq_handler = saa716x_budget_pci_irq, + .i2c_rate = SAA716x_I2C_RATE_100, +}; + + +#define SAA716x_MODEL_TWINHAN_VP6002 "Twinhan/Azurewave VP-6002" +#define SAA716x_DEV_TWINHAN_VP6002 "DVB-S" + +static int saa716x_vp6002_frontend_attach(struct saa716x_adapter *adapter, int count) +{ + struct saa716x_dev *saa716x = adapter->saa716x; + + dprintk(SAA716x_DEBUG, 1, "Adapter (%d) SAA716x frontend Init", count); + dprintk(SAA716x_DEBUG, 1, "Adapter (%d) Device ID=%02x", count, saa716x->pdev->subsystem_device); + + return -ENODEV; +} + +static struct saa716x_config saa716x_vp6002_config = { + .model_name = SAA716x_MODEL_TWINHAN_VP6002, + .dev_type = SAA716x_DEV_TWINHAN_VP6002, + .boot_mode = SAA716x_EXT_BOOT, + .adapters = 1, + .frontend_attach = saa716x_vp6002_frontend_attach, + .irq_handler = saa716x_budget_pci_irq, + .i2c_rate = SAA716x_I2C_RATE_100, +}; + + +#define SAA716x_MODEL_KNC1_DUALS2 "KNC One Dual S2" +#define SAA716x_DEV_KNC1_DUALS2 "1xDVB-S + 1xDVB-S/S2" + +static int saa716x_knc1_duals2_frontend_attach(struct saa716x_adapter *adapter, int count) +{ + struct saa716x_dev *saa716x = adapter->saa716x; + + dprintk(SAA716x_DEBUG, 1, "Adapter (%d) SAA716x frontend Init", count); + dprintk(SAA716x_DEBUG, 1, "Adapter (%d) Device ID=%02x", count, saa716x->pdev->subsystem_device); + + return -ENODEV; +} + +static struct saa716x_config saa716x_knc1_duals2_config = { + .model_name = SAA716x_MODEL_KNC1_DUALS2, + .dev_type = SAA716x_DEV_KNC1_DUALS2, + .boot_mode = SAA716x_EXT_BOOT, + .adapters = 2, + .frontend_attach = saa716x_knc1_duals2_frontend_attach, + .irq_handler = saa716x_budget_pci_irq, + .i2c_rate = SAA716x_I2C_RATE_100, +}; + + +#define SAA716x_MODEL_SKYSTAR2_EXPRESS_HD "SkyStar 2 eXpress HD" +#define SAA716x_DEV_SKYSTAR2_EXPRESS_HD "DVB-S/S2" + +static struct stv090x_config skystar2_stv090x_config = { + .device = STV0903, + .demod_mode = STV090x_SINGLE, + .clk_mode = STV090x_CLK_EXT, + + .xtal = 8000000, + .address = 0x68, + + .ts1_mode = STV090x_TSMODE_DVBCI, + .ts2_mode = STV090x_TSMODE_SERIAL_CONTINUOUS, + + .repeater_level = STV090x_RPTLEVEL_16, + + .tuner_init = NULL, + .tuner_sleep = NULL, + .tuner_set_mode = NULL, + .tuner_set_frequency = NULL, + .tuner_get_frequency = NULL, + .tuner_set_bandwidth = NULL, + .tuner_get_bandwidth = NULL, + .tuner_set_bbgain = NULL, + .tuner_get_bbgain = NULL, + .tuner_set_refclk = NULL, + .tuner_get_status = NULL, +}; + +static int skystar2_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) +{ + int err; + u8 en = 0; + u8 sel = 0; + + switch (voltage) { + case SEC_VOLTAGE_OFF: + en = 0; + break; + + case SEC_VOLTAGE_13: + en = 1; + sel = 0; + break; + + case SEC_VOLTAGE_18: + en = 1; + sel = 1; + break; + + default: + break; + } + + err = stv090x_set_gpio(fe, 2, 0, en, 0); + if (err < 0) + goto exit; + err = stv090x_set_gpio(fe, 3, 0, sel, 0); + if (err < 0) + goto exit; + + return 0; +exit: + return err; +} + +static int skystar2_voltage_boost(struct dvb_frontend *fe, long arg) +{ + int err; + u8 value; + + if (arg) + value = 1; + else + value = 0; + + err = stv090x_set_gpio(fe, 4, 0, value, 0); + if (err < 0) + goto exit; + + return 0; +exit: + return err; +} + +static struct stv6110x_config skystar2_stv6110x_config = { + .addr = 0x60, + .refclk = 16000000, + .clk_div = 2, +}; + +static int skystar2_express_hd_frontend_attach(struct saa716x_adapter *adapter, + int count) +{ + struct saa716x_dev *saa716x = adapter->saa716x; + struct saa716x_i2c *i2c = &saa716x->i2c[SAA716x_I2C_BUS_B]; + struct stv6110x_devctl *ctl; + + if (count < saa716x->config->adapters) { + dprintk(SAA716x_DEBUG, 1, "Adapter (%d) SAA716x frontend Init", + count); + dprintk(SAA716x_DEBUG, 1, "Adapter (%d) Device ID=%02x", count, + saa716x->pdev->subsystem_device); + + saa716x_gpio_set_output(saa716x, 26); + + /* Reset the demodulator */ + saa716x_gpio_write(saa716x, 26, 1); + msleep(10); + saa716x_gpio_write(saa716x, 26, 0); + msleep(10); + saa716x_gpio_write(saa716x, 26, 1); + msleep(10); + + adapter->fe = dvb_attach(stv090x_attach, + &skystar2_stv090x_config, + &i2c->i2c_adapter, + STV090x_DEMODULATOR_0); + + if (adapter->fe) { + dprintk(SAA716x_NOTICE, 1, "found STV0903 @0x%02x", + skystar2_stv090x_config.address); + } else { + goto exit; + } + + adapter->fe->ops.set_voltage = skystar2_set_voltage; + adapter->fe->ops.enable_high_lnb_voltage = skystar2_voltage_boost; + + ctl = dvb_attach(stv6110x_attach, + adapter->fe, + &skystar2_stv6110x_config, + &i2c->i2c_adapter); + + if (ctl) { + dprintk(SAA716x_NOTICE, 1, "found STV6110(A) @0x%02x", + skystar2_stv6110x_config.addr); + + skystar2_stv090x_config.tuner_init = ctl->tuner_init; + skystar2_stv090x_config.tuner_sleep = ctl->tuner_sleep; + skystar2_stv090x_config.tuner_set_mode = ctl->tuner_set_mode; + skystar2_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency; + skystar2_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency; + skystar2_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth; + skystar2_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth; + skystar2_stv090x_config.tuner_set_bbgain = ctl->tuner_set_bbgain; + skystar2_stv090x_config.tuner_get_bbgain = ctl->tuner_get_bbgain; + skystar2_stv090x_config.tuner_set_refclk = ctl->tuner_set_refclk; + skystar2_stv090x_config.tuner_get_status = ctl->tuner_get_status; + + /* call the init function once to initialize + tuner's clock output divider and demod's + master clock */ + if (adapter->fe->ops.init) + adapter->fe->ops.init(adapter->fe); + } else { + goto exit; + } + + dprintk(SAA716x_ERROR, 1, "Done!"); + return 0; + } +exit: + dprintk(SAA716x_ERROR, 1, "Frontend attach failed"); + return -ENODEV; +} + +static struct saa716x_config skystar2_express_hd_config = { + .model_name = SAA716x_MODEL_SKYSTAR2_EXPRESS_HD, + .dev_type = SAA716x_DEV_SKYSTAR2_EXPRESS_HD, + .boot_mode = SAA716x_EXT_BOOT, + .adapters = 1, + .frontend_attach = skystar2_express_hd_frontend_attach, + .irq_handler = saa716x_budget_pci_irq, + .i2c_rate = SAA716x_I2C_RATE_100, + .adap_config = { + { + /* Adapter 0 */ + .ts_port = 1, /* using FGPI 1 */ + .worker = demux_worker + } + } +}; + +static struct ds3103_config s472_ds3103_config = { + .demod_address = 0x68, + .ci_mode = 1, +}; + +static int saa716x_s472_frontend_attach(struct saa716x_adapter *adapter, int count) +{ + struct saa716x_dev *saa716x = adapter->saa716x; + struct saa716x_i2c *i2c = &saa716x->i2c[1]; + + if (count != 0) + return 0; + + dprintk(SAA716x_ERROR, 1, "Probing for DS3103 (DVB-S/S2)"); + adapter->fe = dvb_attach(ds3103_attach, &s472_ds3103_config, + &i2c->i2c_adapter); + + if (adapter->fe == NULL) { + dprintk(SAA716x_ERROR, 1, "Frontend attach failed"); + return -ENODEV; + } + + dprintk(SAA716x_ERROR, 1, "found DS3103 DVB-S/S2 frontend @0x%02x", + s472_ds3103_config.demod_address); + if (NULL == dvb_attach(ts2022_attach, adapter->fe, 0x60, &i2c->i2c_adapter)) + dprintk(SAA716x_ERROR, 1, "ts2022 attach failed"); + else + dprintk(SAA716x_ERROR, 1, "ts2022 attached!"); + + dprintk(SAA716x_ERROR, 1, "Done!"); + return 0; + +} + +static struct saa716x_config tevii_s472_config = { + .model_name = "TeVii S472 DVB-S2", + .dev_type = "DVB-S/S2", + .boot_mode = SAA716x_EXT_BOOT, + .adapters = 1, + .frontend_attach = saa716x_s472_frontend_attach, + .irq_handler = saa716x_budget_pci_irq, + .i2c_rate = SAA716x_I2C_RATE_100, + .adap_config = { + { + /* Adapter 0 */ + .ts_port = 1, /* using FGPI 1 */ + .worker = demux_worker + } + } +}; + +static struct pci_device_id saa716x_budget_pci_table[] = { + + MAKE_ENTRY(TWINHAN_TECHNOLOGIES, TWINHAN_VP_1028, SAA7160, &saa716x_vp1028_config), /* VP-1028 */ + MAKE_ENTRY(TWINHAN_TECHNOLOGIES, TWINHAN_VP_3071, SAA7160, &saa716x_vp3071_config), /* VP-3071 */ + MAKE_ENTRY(TWINHAN_TECHNOLOGIES, TWINHAN_VP_6002, SAA7160, &saa716x_vp6002_config), /* VP-6002 */ + MAKE_ENTRY(KNC_One, KNC_Dual_S2, SAA7160, &saa716x_knc1_duals2_config), + MAKE_ENTRY(TECHNISAT, SKYSTAR2_EXPRESS_HD, SAA7160, &skystar2_express_hd_config), + MAKE_ENTRY(TEVII, TEVII_S472, SAA7160, &tevii_s472_config), + { } +}; +MODULE_DEVICE_TABLE(pci, saa716x_budget_pci_table); + +static struct pci_driver saa716x_budget_pci_driver = { + .name = DRIVER_NAME, + .id_table = saa716x_budget_pci_table, + .probe = saa716x_budget_pci_probe, + .remove = saa716x_budget_pci_remove, +}; + +static int saa716x_budget_init(void) +{ + return pci_register_driver(&saa716x_budget_pci_driver); +} + +static void saa716x_budget_exit(void) +{ + return pci_unregister_driver(&saa716x_budget_pci_driver); +} + +module_init(saa716x_budget_init); +module_exit(saa716x_budget_exit); + +MODULE_DESCRIPTION("SAA716x Budget driver"); +MODULE_AUTHOR("Manu Abraham"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/common/saa716x/saa716x_budget.h b/drivers/media/common/saa716x/saa716x_budget.h new file mode 100644 index 0000000..d6b8c46 --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_budget.h @@ -0,0 +1,17 @@ +#ifndef __SAA716x_BUDGET_H +#define __SAA716x_BUDGET_H + +#define TWINHAN_TECHNOLOGIES 0x1822 +#define TWINHAN_VP_3071 0x0039 +#define TWINHAN_VP_1028 0x0044 +#define TWINHAN_VP_6002 0x0047 + +#define KNC_One 0x1894 +#define KNC_Dual_S2 0x0110 + +#define TECHNISAT 0x1AE4 +#define SKYSTAR2_EXPRESS_HD 0x0700 +#define TEVII 0x9022 +#define TEVII_S472 0xd472 + +#endif /* __SAA716x_BUDGET_H */ diff --git a/drivers/media/common/saa716x/saa716x_cgu.c b/drivers/media/common/saa716x/saa716x_cgu.c new file mode 100644 index 0000000..a0ffb04 --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_cgu.c @@ -0,0 +1,539 @@ +#include + +#include "saa716x_mod.h" + +#include "saa716x_cgu_reg.h" +#include "saa716x_spi.h" +#include "saa716x_priv.h" + +u32 cgu_clk[14] = { + CGU_FDC_0, + CGU_FDC_1, + CGU_FDC_2, + CGU_FDC_3, + CGU_FDC_4, + CGU_FDC_5, + CGU_FDC_6, + CGU_FDC_7, + CGU_FDC_8, + CGU_FDC_9, + CGU_FDC_10, + CGU_FDC_11, + CGU_FDC_12, + CGU_FDC_13 +}; + +char *clk_desc[14] = { + "Clk PSS", + "Clk DCS", + "Clk SPI", + "Clk I2C/Boot", + "Clk PHI", + "Clk VI0", + "Clk VI1", + "Clk FGPI0", + "Clk FGPI1", + "Clk FGPI2", + "Clk FGPI3", + "Clk AI0", + "Clk AI1", + "Clk Phy" +}; + +int saa716x_getbootscript_setup(struct saa716x_dev *saa716x) +{ + struct saa716x_cgu *cgu = &saa716x->cgu; + + u8 i; + s8 N = 0; + s16 M = 0; + + SAA716x_EPWR(CGU, CGU_PCR_0_6, CGU_PCR_RUN); /* GREG */ + SAA716x_EPWR(CGU, CGU_PCR_0_3, CGU_PCR_RUN); /* PSS_MMU */ + SAA716x_EPWR(CGU, CGU_PCR_0_4, CGU_PCR_RUN); /* PSS_DTL2MTL */ + SAA716x_EPWR(CGU, CGU_PCR_0_5, CGU_PCR_RUN); /* MSI */ + SAA716x_EPWR(CGU, CGU_PCR_3_2, CGU_PCR_RUN); /* I2C */ + SAA716x_EPWR(CGU, CGU_PCR_4_1, CGU_PCR_RUN); /* PHI */ + SAA716x_EPWR(CGU, CGU_PCR_0_7, CGU_PCR_RUN); /* GPIO */ + SAA716x_EPWR(CGU, CGU_PCR_2_1, CGU_PCR_RUN); /* SPI */ + SAA716x_EPWR(CGU, CGU_PCR_1_1, CGU_PCR_RUN); /* DCS */ + SAA716x_EPWR(CGU, CGU_PCR_3_1, CGU_PCR_RUN); /* BOOT */ + + /* get all dividers */ + for (i = 0; i < CGU_CLKS; i++) { + cgu->clk_boot_div[i] = SAA716x_EPRD(CGU, cgu_clk[i]); + cgu->clk_curr_div[i] = cgu->clk_boot_div[i]; + + N = (cgu->clk_boot_div[i] >> 11) & 0xff; + N *= -1; + M = ((cgu->clk_boot_div[i] >> 3) & 0xff) + N; + + if (M) + cgu->clk_freq[i] = (u32 ) N * PLL_FREQ / (u32 ) M; + else + cgu->clk_freq[i] = 0; + + dprintk(SAA716x_DEBUG, 1, "Domain %d: %s <0x%02x> Divider: 0x%x --> N=%d, M=%d, freq=%d", + i, clk_desc[i], cgu_clk[i], cgu->clk_boot_div[i], N, M, cgu->clk_freq[i]); + } + /* store clock settings */ + cgu->clk_vi_0[0] = cgu->clk_freq[CLK_DOMAIN_VI0]; + cgu->clk_vi_0[1] = cgu->clk_freq[CLK_DOMAIN_VI0]; + cgu->clk_vi_0[2] = cgu->clk_freq[CLK_DOMAIN_VI0]; + cgu->clk_vi_1[0] = cgu->clk_freq[CLK_DOMAIN_VI1]; + cgu->clk_vi_1[1] = cgu->clk_freq[CLK_DOMAIN_VI1]; + cgu->clk_vi_1[2] = cgu->clk_freq[CLK_DOMAIN_VI1]; + + return 0; +} + +int saa716x_set_clk_internal(struct saa716x_dev *saa716x, u32 port) +{ + struct saa716x_cgu *cgu = &saa716x->cgu; + + u8 delay = 1; + + switch (port) { + case PORT_VI0_VIDEO: + cgu->clk_int_port[PORT_VI0_VIDEO] = 1; + + if (!cgu->clk_int_port[PORT_VI0_VBI]) { + delay = 0; + break; + } + + SAA716x_CGU_CLKRUN(5); + break; + + case PORT_VI0_VBI: + cgu->clk_int_port[PORT_VI0_VBI] = 1; + + if (!cgu->clk_int_port[PORT_VI0_VIDEO]) { + delay = 0; + break; + } + + SAA716x_CGU_CLKRUN(5); + break; + + case PORT_VI1_VIDEO: + cgu->clk_int_port[PORT_VI1_VIDEO] = 1; + + if (!cgu->clk_int_port[PORT_VI1_VBI]) { + delay = 0; + break; + } + + SAA716x_CGU_CLKRUN(6); + break; + + case PORT_VI1_VBI: + cgu->clk_int_port[PORT_VI1_VBI] = 1; + + if (!cgu->clk_int_port[PORT_VI1_VIDEO]) { + delay = 0; + break; + } + + SAA716x_CGU_CLKRUN(6); + break; + + case PORT_FGPI0: + cgu->clk_int_port[PORT_FGPI0] = 1; + SAA716x_CGU_CLKRUN(7); + break; + + case PORT_FGPI1: + cgu->clk_int_port[PORT_FGPI1] = 1; + SAA716x_CGU_CLKRUN(8); + break; + + case PORT_FGPI2: + cgu->clk_int_port[PORT_FGPI2] = 1; + SAA716x_CGU_CLKRUN(9); + break; + + case PORT_FGPI3: + cgu->clk_int_port[PORT_FGPI3] = 1; + SAA716x_CGU_CLKRUN(10); + break; + + case PORT_AI0: + cgu->clk_int_port[PORT_AI0] = 1; + SAA716x_CGU_CLKRUN(11); + break; + + case PORT_AI1: + cgu->clk_int_port[PORT_AI1] = 1; + SAA716x_CGU_CLKRUN(12); + break; + + case PORT_ALL: + SAA716x_CGU_CLKRUN(5); + SAA716x_CGU_CLKRUN(6); + SAA716x_CGU_CLKRUN(7); + SAA716x_CGU_CLKRUN(8); + SAA716x_CGU_CLKRUN(9); + SAA716x_CGU_CLKRUN(10); + SAA716x_CGU_CLKRUN(11); + SAA716x_CGU_CLKRUN(12); + + cgu->clk_int_port[PORT_VI0_VIDEO] = 1; + cgu->clk_int_port[PORT_VI0_VBI] = 1; + cgu->clk_int_port[PORT_VI1_VIDEO] = 1; + cgu->clk_int_port[PORT_VI1_VBI] = 1; + cgu->clk_int_port[PORT_FGPI0] = 1; + cgu->clk_int_port[PORT_FGPI1] = 1; + cgu->clk_int_port[PORT_FGPI2] = 1; + cgu->clk_int_port[PORT_FGPI3] = 1; + cgu->clk_int_port[PORT_AI0] = 1; + cgu->clk_int_port[PORT_AI1] = 1; + break; + + default: + dprintk(SAA716x_ERROR, 1, "Unknown port <%02x>", port); + delay = 0; + break; + } + + /* wait for PLL */ + if (delay) + msleep(1); + + return 0; +} + +int saa716x_set_clk_external(struct saa716x_dev *saa716x, u32 port) +{ + struct saa716x_cgu *cgu = &saa716x->cgu; + + u8 delay = 1; + + switch (port) { + case PORT_VI0_VIDEO: + cgu->clk_int_port[PORT_VI0_VIDEO] = 0; + + if (!cgu->clk_int_port[PORT_VI0_VBI]) { + delay = 0; + break; + } + + SAA716x_EPWR(CGU, CGU_FS1_5, 0x2); /* VI 0 clk */ + SAA716x_EPWR(CGU, CGU_ESR_5, 0x0); /* disable divider */ + break; + + case PORT_VI0_VBI: + cgu->clk_int_port[PORT_VI0_VBI] = 0; + + if (!cgu->clk_int_port[PORT_VI0_VIDEO]) { + delay = 0; + break; + } + + SAA716x_EPWR(CGU, CGU_FS1_5, 0x2); /* VI 0 clk */ + SAA716x_EPWR(CGU, CGU_ESR_5, 0x0); /* disable divider */ + break; + + case PORT_VI1_VIDEO: + cgu->clk_int_port[PORT_VI1_VIDEO] = 0; + + if (!cgu->clk_int_port[PORT_VI1_VBI]) { + delay = 0; + break; + } + + SAA716x_EPWR(CGU, CGU_FS1_6, 0x3); /* VI 1 clk */ + SAA716x_EPWR(CGU, CGU_ESR_6, 0x0); /* disable divider */ + break; + + case PORT_VI1_VBI: + cgu->clk_int_port[PORT_VI1_VBI] = 0; + + if (!cgu->clk_int_port[PORT_VI1_VIDEO]) { + delay = 0; + break; + } + + SAA716x_EPWR(CGU, CGU_FS1_6, 0x3); /* VI 1 clk */ + SAA716x_EPWR(CGU, CGU_ESR_6, 0x0); /* disable divider */ + break; + + case PORT_FGPI0: + cgu->clk_int_port[PORT_FGPI0] = 0; + + SAA716x_EPWR(CGU, CGU_FS1_7, 0x4); /* FGPI 0 clk */ + SAA716x_EPWR(CGU, CGU_ESR_7, 0x0); /* disable divider */ + break; + + case PORT_FGPI1: + cgu->clk_int_port[PORT_FGPI1] = 0; + + SAA716x_EPWR(CGU, CGU_FS1_8, 0x5); /* FGPI 1 clk */ + SAA716x_EPWR(CGU, CGU_ESR_8, 0x0); /* disable divider */ + break; + + case PORT_FGPI2: + cgu->clk_int_port[PORT_FGPI2] = 0; + + SAA716x_EPWR(CGU, CGU_FS1_9, 0x6); /* FGPI 2 clk */ + SAA716x_EPWR(CGU, CGU_ESR_9, 0x0); /* disable divider */ + break; + + case PORT_FGPI3: + cgu->clk_int_port[PORT_FGPI3] = 0; + + SAA716x_EPWR(CGU, CGU_FS1_10, 0x7); /* FGPI 3 clk */ + SAA716x_EPWR(CGU, CGU_ESR_10, 0x0); /* disable divider */ + break; + + case PORT_AI0: + cgu->clk_int_port[PORT_AI0] = 1; + + SAA716x_EPWR(CGU, CGU_FS1_11, 0x8); /* AI 0 clk */ + SAA716x_EPWR(CGU, CGU_ESR_11, 0x0); /* disable divider */ + break; + + case PORT_AI1: + cgu->clk_int_port[PORT_AI1] = 1; + + SAA716x_EPWR(CGU, CGU_FS1_12, 0x9); /* AI 1 clk */ + SAA716x_EPWR(CGU, CGU_ESR_12, 0x0); /* disable divider */ + break; + + default: + dprintk(SAA716x_ERROR, 1, "Unknown port <%02x>", port); + delay = 0; + break; + + } + + if (delay) + msleep(1); + + return 0; +} + +int saa716x_get_clk(struct saa716x_dev *saa716x, + enum saa716x_clk_domain domain, + u32 *frequency) +{ + struct saa716x_cgu *cgu = &saa716x->cgu; + + switch (domain) { + case CLK_DOMAIN_PSS: + case CLK_DOMAIN_DCS: + case CLK_DOMAIN_SPI: + case CLK_DOMAIN_I2C: + case CLK_DOMAIN_PHI: + case CLK_DOMAIN_VI0: + case CLK_DOMAIN_VI1: + case CLK_DOMAIN_FGPI0: + case CLK_DOMAIN_FGPI1: + case CLK_DOMAIN_FGPI2: + case CLK_DOMAIN_FGPI3: + case CLK_DOMAIN_AI0: + case CLK_DOMAIN_AI1: + case CLK_DOMAIN_PHY: + *frequency = cgu->clk_freq[domain]; + break; + + case CLK_DOMAIN_VI0VBI: + *frequency = cgu->clk_freq[CLK_DOMAIN_VI0]; + break; + + case CLK_DOMAIN_VI1VBI: + *frequency =cgu->clk_freq[CLK_DOMAIN_VI1]; + break; + default: + dprintk(SAA716x_ERROR, 1, "Error Clock domain <%02x>", domain); + break; + } + + return 0; +} + +int saa716x_set_clk(struct saa716x_dev *saa716x, + enum saa716x_clk_domain domain, + u32 frequency) +{ + struct saa716x_cgu *cgu = &saa716x->cgu; + + u32 M = 1, N = 1, reset, i; + s8 N_tmp, M_tmp, sub, add, lsb; + + + if (cgu->clk_freq_min > frequency) + frequency = cgu->clk_freq_min; + + if (cgu->clk_freq_max < frequency) + frequency = cgu->clk_freq_max; + + switch (domain) { + case CLK_DOMAIN_PSS: + case CLK_DOMAIN_DCS: + case CLK_DOMAIN_SPI: + case CLK_DOMAIN_I2C: + case CLK_DOMAIN_PHI: + case CLK_DOMAIN_FGPI0: + case CLK_DOMAIN_FGPI1: + case CLK_DOMAIN_FGPI2: + case CLK_DOMAIN_FGPI3: + case CLK_DOMAIN_AI0: + case CLK_DOMAIN_AI1: + case CLK_DOMAIN_PHY: + + if (frequency == cgu->clk_freq[domain]) + return 0; /* same frequency */ + break; + + case CLK_DOMAIN_VI0: + + if (frequency == cgu->clk_vi_0[1]) { + return 0; + + } else if (frequency == cgu->clk_vi_0[0]) { + cgu->clk_vi_0[1] = frequency; /* store */ + + if (frequency == cgu->clk_vi_0[2]) + return 0; + + } else { + cgu->clk_vi_0[1] = frequency; + + if (frequency != cgu->clk_vi_0[2]) + return 0; + + } + break; + + case CLK_DOMAIN_VI1: + if (frequency == cgu->clk_vi_1[1]) { + return 0; + + } else if (frequency == cgu->clk_vi_1[0]) { + cgu->clk_vi_1[1] = frequency; /* store */ + + if (frequency == cgu->clk_vi_1[2]) + return 0; + + } else { + cgu->clk_vi_1[1] = frequency; + + if (frequency != cgu->clk_vi_1[2]) + return 0; + + } + break; + + case CLK_DOMAIN_VI0VBI: + if (frequency == cgu->clk_vi_0[2]) { + return 0; + + } else if (frequency == cgu->clk_vi_0[0]) { + cgu->clk_vi_0[2] = frequency; /* store */ + + if (frequency == cgu->clk_vi_0[1]) + return 0; + + } else { + cgu->clk_vi_0[2] = frequency; /* store */ + + if (frequency != cgu->clk_vi_0[1]) + return 0; + + } + domain = CLK_DOMAIN_VI0; /* change domain */ + break; + + case CLK_DOMAIN_VI1VBI: + if (frequency == cgu->clk_vi_1[2]) { + return 0; + + } else if (frequency == cgu->clk_vi_1[0]) { + cgu->clk_vi_1[2] = frequency; /* store */ + + if (frequency == cgu->clk_vi_1[1]) + return 0; + + } else { + cgu->clk_vi_1[2] = frequency; /* store */ + + if (frequency != cgu->clk_vi_1[1]) + return 0; + + } + domain = CLK_DOMAIN_VI1; /* change domain */ + break; + } + + /* calculate divider */ + do { + M = (N * PLL_FREQ) / frequency; + if (M == 0) + N++; + + } while (M == 0); + + /* calculate frequency */ + cgu->clk_freq[domain] = (N * PLL_FREQ) / M; + + N_tmp = N & 0xff; + M_tmp = M & 0xff; + sub = -N_tmp; + add = M_tmp - N_tmp; + lsb = 4; /* run */ + + if (((10 * N) / M) < 5) + lsb |= 1; /* stretch */ + + /* store new divider */ + cgu->clk_curr_div[domain] = sub & 0xff; + cgu->clk_curr_div[domain] <<= 8; + cgu->clk_curr_div[domain] = add & 0xff; + cgu->clk_curr_div[domain] <<= 3; + cgu->clk_curr_div[domain] |= lsb; + + dprintk(SAA716x_DEBUG, 1, "Domain <0x%02x> Frequency <%d> Set Freq <%d> N=%d M=%d Divider <0x%02x>", + domain, + frequency, + cgu->clk_freq[domain], + N, + M, + cgu->clk_curr_div[domain]); + + reset = 0; + + /* Reset */ + SAA716x_EPWR(CGU, cgu_clk[domain], cgu->clk_curr_div[domain] | 0x2); + + /* Reset disable */ + for (i = 0; i < 1000; i++) { + msleep(10); + reset = SAA716x_EPRD(CGU, cgu_clk[domain]); + + if (cgu->clk_curr_div[domain == reset]) + break; + } + + if (cgu->clk_curr_div[domain] != reset) + SAA716x_EPWR(CGU, cgu_clk[domain], cgu->clk_curr_div[domain]); + + return 0; +} + +int saa716x_cgu_init(struct saa716x_dev *saa716x) +{ + struct saa716x_cgu *cgu = &saa716x->cgu; + + cgu->clk_freq_min = PLL_FREQ / 255; + if (PLL_FREQ > (cgu->clk_freq_min * 255)) + cgu->clk_freq_min++; + + cgu->clk_freq_max = PLL_FREQ; + + saa716x_getbootscript_setup(saa716x); + saa716x_set_clk_internal(saa716x, PORT_ALL); + + return 0; +} +EXPORT_SYMBOL(saa716x_cgu_init); diff --git a/drivers/media/common/saa716x/saa716x_cgu.h b/drivers/media/common/saa716x/saa716x_cgu.h new file mode 100644 index 0000000..5353cf2 --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_cgu.h @@ -0,0 +1,61 @@ +#ifndef __SAA716x_CGU_H +#define __SAA716x_CGU_H + +#define PLL_FREQ 2500 + +#define SAA716x_CGU_CLKRUN(__reg) do { \ + SAA716x_EPWR(CGU, CGU_PCR_##__reg, CGU_PCR_RUN); /* Run */ \ + SAA716x_EPWR(CGU, CGU_SCR_##__reg, CGU_SCR_ENF1); /* Switch */ \ + SAA716x_EPWR(CGU, CGU_FS1_##__reg, 0x00000000); /* PLL Clk */ \ + SAA716x_EPWR(CGU, CGU_ESR_##__reg, CGU_ESR_FD_EN); /* Frac div */ \ +} while (0) + +enum saa716x_clk_domain { + CLK_DOMAIN_PSS = 0, + CLK_DOMAIN_DCS = 1, + CLK_DOMAIN_SPI = 2, + CLK_DOMAIN_I2C = 3, + CLK_DOMAIN_PHI = 4, + CLK_DOMAIN_VI0 = 5, + CLK_DOMAIN_VI1 = 6, + CLK_DOMAIN_FGPI0 = 7, + CLK_DOMAIN_FGPI1 = 8, + CLK_DOMAIN_FGPI2 = 9, + CLK_DOMAIN_FGPI3 = 10, + CLK_DOMAIN_AI0 = 11, + CLK_DOMAIN_AI1 = 12, + CLK_DOMAIN_PHY = 13, + CLK_DOMAIN_VI0VBI = 14, + CLK_DOMAIN_VI1VBI = 15 +}; + +#define PORT_VI0_VIDEO 0 +#define PORT_VI0_VBI 2 +#define PORT_VI1_VIDEO 3 +#define PORT_VI1_VBI 5 +#define PORT_FGPI0 6 +#define PORT_FGPI1 7 +#define PORT_FGPI2 8 +#define PORT_FGPI3 9 +#define PORT_AI0 10 +#define PORT_AI1 11 +#define PORT_ALL 12 + +#define CGU_CLKS 14 + +struct saa716x_cgu { + u8 clk_int_port[12]; + u32 clk_vi_0[3]; + u32 clk_vi_1[3]; + u32 clk_boot_div[CGU_CLKS]; + u32 clk_curr_div[CGU_CLKS]; + u32 clk_freq[CGU_CLKS]; + u32 clk_freq_min; + u32 clk_freq_max; +}; + +extern int saa716x_cgu_init(struct saa716x_dev *saa716x); +extern int saa716x_set_clk_internal(struct saa716x_dev *saa716x, u32 port); +extern int saa716x_set_clk_external(struct saa716x_dev *saa716x, u32 port); + +#endif /* __SAA716x_CGU_H */ diff --git a/drivers/media/common/saa716x/saa716x_cgu_reg.h b/drivers/media/common/saa716x/saa716x_cgu_reg.h new file mode 100644 index 0000000..f7d82ae --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_cgu_reg.h @@ -0,0 +1,178 @@ +#ifndef __SAA716x_CGU_REG_H +#define __SAA716x_CGU_REG_H + +/* -------------- CGU Registers -------------- */ + +#define CGU_SCR_0 0x000 +#define CGU_SCR_1 0x004 +#define CGU_SCR_2 0x008 +#define CGU_SCR_3 0x00c +#define CGU_SCR_4 0x010 +#define CGU_SCR_5 0x014 +#define CGU_SCR_6 0x018 +#define CGU_SCR_7 0x01c +#define CGU_SCR_8 0x020 +#define CGU_SCR_9 0x024 +#define CGU_SCR_10 0x028 +#define CGU_SCR_11 0x02c +#define CGU_SCR_12 0x030 +#define CGU_SCR_13 0x034 +#define CGU_SCR_STOP (0x00000001 << 3) +#define CGU_SCR_RESET (0x00000001 << 2) +#define CGU_SCR_ENF2 (0x00000001 << 1) +#define CGU_SCR_ENF1 (0x00000001 << 0) + +#define CGU_FS1_0 0x038 +#define CGU_FS1_1 0x03c +#define CGU_FS1_2 0x040 +#define CGU_FS1_3 0x044 +#define CGU_FS1_4 0x048 +#define CGU_FS1_5 0x04c +#define CGU_FS1_6 0x050 +#define CGU_FS1_7 0x054 +#define CGU_FS1_8 0x058 +#define CGU_FS1_9 0x05c +#define CGU_FS1_10 0x060 +#define CGU_FS1_11 0x064 +#define CGU_FS1_12 0x068 +#define CGU_FS1_13 0x06c +#define CGU_FS1_PLL (0x00000000 << 0) + + +#define CGU_FS2_0 0x070 +#define CGU_FS2_1 0x074 +#define CGU_FS2_2 0x078 +#define CGU_FS2_3 0x07c +#define CGU_FS2_4 0x080 +#define CGU_FS2_5 0x084 +#define CGU_FS2_6 0x088 +#define CGU_FS2_7 0x08c +#define CGU_FS2_8 0x090 +#define CGU_FS2_9 0x094 +#define CGU_FS2_10 0x098 +#define CGU_FS2_11 0x09c +#define CGU_FS2_12 0x0a0 +#define CGU_FS2_13 0x0a4 + +#define CGU_SSR_0 0x0a8 +#define CGU_SSR_1 0x0ac +#define CGU_SSR_2 0x0b0 +#define CGU_SSR_3 0x0b4 +#define CGU_SSR_4 0x0b8 +#define CGU_SSR_5 0x0bc +#define CGU_SSR_6 0x0c0 +#define CGU_SSR_7 0x0c4 +#define CGU_SSR_8 0x0c8 +#define CGU_SSR_9 0x0cc +#define CGU_SSR_10 0x0d0 +#define CGU_SSR_11 0x0d4 +#define CGU_SSR_12 0x0d8 +#define CGU_SSR_13 0x0dc + +#define CGU_PCR_0_0 0x0e0 +#define CGU_PCR_0_1 0x0e4 +#define CGU_PCR_0_2 0x0e8 +#define CGU_PCR_0_3 0x0ec +#define CGU_PCR_0_4 0x0f0 +#define CGU_PCR_0_5 0x0f4 +#define CGU_PCR_0_6 0x0f8 +#define CGU_PCR_0_7 0x0fc +#define CGU_PCR_1_0 0x100 +#define CGU_PCR_1_1 0x104 +#define CGU_PCR_2_0 0x108 +#define CGU_PCR_2_1 0x10c +#define CGU_PCR_3_0 0x110 +#define CGU_PCR_3_1 0x114 +#define CGU_PCR_3_2 0x118 +#define CGU_PCR_4_0 0x11c +#define CGU_PCR_4_1 0x120 +#define CGU_PCR_5 0x124 +#define CGU_PCR_6 0x128 +#define CGU_PCR_7 0x12c +#define CGU_PCR_8 0x130 +#define CGU_PCR_9 0x134 +#define CGU_PCR_10 0x138 +#define CGU_PCR_11 0x13c +#define CGU_PCR_12 0x140 +#define CGU_PCR_13 0x144 +#define CGU_PCR_WAKE_EN (0x00000001 << 2) +#define CGU_PCR_AUTO (0x00000001 << 1) +#define CGU_PCR_RUN (0x00000001 << 0) + + +#define CGU_PSR_0_0 0x148 +#define CGU_PSR_0_1 0x14c +#define CGU_PSR_0_2 0x150 +#define CGU_PSR_0_3 0x154 +#define CGU_PSR_0_4 0x158 +#define CGU_PSR_0_5 0x15c +#define CGU_PSR_0_6 0x160 +#define CGU_PSR_0_7 0x164 +#define CGU_PSR_1_0 0x168 +#define CGU_PSR_1_1 0x16c +#define CGU_PSR_2_0 0x170 +#define CGU_PSR_2_1 0x174 +#define CGU_PSR_3_0 0x178 +#define CGU_PSR_3_1 0x17c +#define CGU_PSR_3_2 0x180 +#define CGU_PSR_4_0 0x184 +#define CGU_PSR_4_1 0x188 +#define CGU_PSR_5 0x18c +#define CGU_PSR_6 0x190 +#define CGU_PSR_7 0x194 +#define CGU_PSR_8 0x198 +#define CGU_PSR_9 0x19c +#define CGU_PSR_10 0x1a0 +#define CGU_PSR_11 0x1a4 +#define CGU_PSR_12 0x1a8 +#define CGU_PSR_13 0x1ac + +#define CGU_ESR_0_0 0x1b0 +#define CGU_ESR_0_1 0x1b4 +#define CGU_ESR_0_2 0x1b8 +#define CGU_ESR_0_3 0x1bc +#define CGU_ESR_0_4 0x1c0 +#define CGU_ESR_0_5 0x1c4 +#define CGU_ESR_0_6 0x1c8 +#define CGU_ESR_0_7 0x1cc +#define CGU_ESR_1_0 0x1d0 +#define CGU_ESR_1_1 0x1d4 +#define CGU_ESR_2_0 0x1d8 +#define CGU_ESR_2_1 0x1dc +#define CGU_ESR_3_0 0x1e0 +#define CGU_ESR_3_1 0x1e4 +#define CGU_ESR_3_2 0x1e8 +#define CGU_ESR_4_0 0x1ec +#define CGU_ESR_4_1 0x1f0 +#define CGU_ESR_5 0x1f4 +#define CGU_ESR_6 0x1f8 +#define CGU_ESR_7 0x1fc +#define CGU_ESR_8 0x200 +#define CGU_ESR_9 0x204 +#define CGU_ESR_10 0x208 +#define CGU_ESR_11 0x20c +#define CGU_ESR_12 0x210 +#define CGU_ESR_13 0x214 +#define CGU_ESR_FD_EN (0x00000001 << 0) + +#define CGU_FDC_0 0x218 +#define CGU_FDC_1 0x21c +#define CGU_FDC_2 0x220 +#define CGU_FDC_3 0x224 +#define CGU_FDC_4 0x228 +#define CGU_FDC_5 0x22c +#define CGU_FDC_6 0x230 +#define CGU_FDC_7 0x234 +#define CGU_FDC_8 0x238 +#define CGU_FDC_9 0x23c +#define CGU_FDC_10 0x240 +#define CGU_FDC_11 0x244 +#define CGU_FDC_12 0x248 +#define CGU_FDC_13 0x24c +#define CGU_FDC_STRETCH (0x00000001 << 0) +#define CGU_FDC_RESET (0x00000001 << 1) +#define CGU_FDC_RUN1 (0x00000001 << 2) +#define CGU_FDC_MADD (0x000000ff << 3) +#define CGU_FDC_MSUB (0x000000ff << 11) + +#endif /* __SAA716x_CGU_REG_H */ diff --git a/drivers/media/common/saa716x/saa716x_dcs_reg.h b/drivers/media/common/saa716x/saa716x_dcs_reg.h new file mode 100644 index 0000000..26dba68 --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_dcs_reg.h @@ -0,0 +1,56 @@ +#ifndef __SAA716x_DCS_REG_H +#define __SAA716x_DCS_REG_H + +/* -------------- DCS Registers -------------- */ + +#define DCSC_CTRL 0x000 +#define DCSC_SEL_PLLDI (0x03ffffff << 5) +#define DCSC_TOUT_SEL (0x0000000f << 1) +#define DCSC_TOUT_OFF (0x00000001 << 0) + +#define DCSC_ADDR 0x00c +#define DCSC_ERR_TOUT_ADDR (0x3fffffff << 2) + +#define DCSC_STAT 0x010 +#define DCSC_ERR_TOUT_GNT (0x0000001f << 24) +#define DCSC_ERR_TOUT_SEL (0x0000007f << 10) +#define DCSC_ERR_TOUT_READ (0x00000001 << 8) +#define DCSC_ERR_TOUT_MASK (0x0000000f << 4) +#define DCSC_ERR_ACK (0x00000001 << 1) + +#define DCSC_FEATURES 0x040 +#define DCSC_UNIQUE_ID (0x00000007 << 16) +#define DCSC_SECURITY (0x00000001 << 14) +#define DCSC_NUM_BASE_REGS (0x00000003 << 11) +#define DCSC_NUM_TARGETS (0x0000001f << 5) +#define DCSC_NUM_INITIATORS (0x0000001f << 0) + +#define DCSC_BASE_REG0 0x100 +#define DCSC_BASE_N_REG (0x00000fff << 20) + +#define DCSC_INT_CLR_ENABLE 0xfd8 +#define DCSC_INT_CLR_ENABLE_TOUT (0x00000001 << 1) +#define DCSC_INT_CLR_ENABLE_ERROR (0x00000001 << 0) + +#define DCSC_INT_SET_ENABLE 0xfdc +#define DCSC_INT_SET_ENABLE_TOUT (0x00000001 << 1) +#define DCSC_INT_SET_ENABLE_ERROR (0x00000001 << 0) + +#define DCSC_INT_STATUS 0xfe0 +#define DCSC_INT_STATUS_TOUT (0x00000001 << 1) +#define DCSC_INT_STATUS_ERROR (0x00000001 << 0) + +#define DCSC_INT_ENABLE 0xfe4 +#define DCSC_INT_ENABLE_TOUT (0x00000001 << 1) +#define DCSC_INT_ENABLE_ERROR (0x00000001 << 0) + +#define DCSC_INT_CLR_STATUS 0xfe8 +#define DCSC_INT_CLEAR_TOUT (0x00000001 << 1) +#define DCSC_INT_CLEAR_ERROR (0x00000001 << 0) + +#define DCSC_INT_SET_STATUS 0xfec +#define DCSC_INT_SET_TOUT (0x00000001 << 1) +#define DCSC_INT_SET_ERROR (0x00000001 << 0) + + +#endif /* __SAA716x_DCS_REG_H */ diff --git a/drivers/media/common/saa716x/saa716x_dma.c b/drivers/media/common/saa716x/saa716x_dma.c new file mode 100644 index 0000000..21d1dd8 --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_dma.c @@ -0,0 +1,306 @@ +#include +#include +#include +#include +#include + +#include "saa716x_dma.h" +#include "saa716x_spi.h" +#include "saa716x_priv.h" + +/* Allocates one page of memory, which is stores the data of one + * 716x page table. The result gets stored in the passed DMA buffer + * structure. + */ +static int saa716x_allocate_ptable(struct saa716x_dmabuf *dmabuf) +{ + struct saa716x_dev *saa716x = dmabuf->saa716x; + struct pci_dev *pdev = saa716x->pdev; + + dprintk(SAA716x_DEBUG, 1, "SG Page table allocate"); + dmabuf->mem_ptab_virt = (void *) __get_free_page(GFP_KERNEL); + + if (dmabuf->mem_ptab_virt == NULL) { + dprintk(SAA716x_ERROR, 1, "ERROR: Out of pages !"); + return -ENOMEM; + } + + dmabuf->mem_ptab_phys = dma_map_single(&pdev->dev, + dmabuf->mem_ptab_virt, + SAA716x_PAGE_SIZE, + DMA_TO_DEVICE); + + if (dmabuf->mem_ptab_phys == 0) { + dprintk(SAA716x_ERROR, 1, "ERROR: map memory failed !"); + return -ENOMEM; + } + + BUG_ON(!(((unsigned long) dmabuf->mem_ptab_phys % SAA716x_PAGE_SIZE) == 0)); + + return 0; +} + +static void saa716x_free_ptable(struct saa716x_dmabuf *dmabuf) +{ + struct saa716x_dev *saa716x = dmabuf->saa716x; + struct pci_dev *pdev = saa716x->pdev; + + BUG_ON(dmabuf == NULL); + dprintk(SAA716x_DEBUG, 1, "SG Page table free"); + + /* free physical PCI memory */ + if (dmabuf->mem_ptab_phys != 0) { + dma_unmap_single(&pdev->dev, + dmabuf->mem_ptab_phys, + SAA716x_PAGE_SIZE, + DMA_TO_DEVICE); + + dmabuf->mem_ptab_phys = 0; + } + + /* free kernel memory */ + if (dmabuf->mem_ptab_virt != NULL) { + free_page((unsigned long) dmabuf->mem_ptab_virt); + dmabuf->mem_ptab_virt = NULL; + } +} + +static void saa716x_dmabuf_sgfree(struct saa716x_dmabuf *dmabuf) +{ + struct saa716x_dev *saa716x = dmabuf->saa716x; + + BUG_ON(dmabuf == NULL); + dprintk(SAA716x_DEBUG, 1, "SG free"); + + dmabuf->mem_virt = NULL; + if (dmabuf->mem_virt_noalign != NULL) { + if (dmabuf->dma_type == SAA716x_DMABUF_INT) + vfree(dmabuf->mem_virt_noalign); + + dmabuf->mem_virt_noalign = NULL; + } + + if (dmabuf->sg_list != NULL) { + kfree(dmabuf->sg_list); + dmabuf->sg_list = NULL; + } +} + +/* + * Create a SG, when an allocated buffer is passed to it, + * otherwise the needed memory gets allocated by itself + */ +static int saa716x_dmabuf_sgalloc(struct saa716x_dmabuf *dmabuf, void *buf, int size) +{ + struct saa716x_dev *saa716x = dmabuf->saa716x; + struct scatterlist *list; + struct page *pg; + + int i, pages; + + BUG_ON(!(size > 0)); + BUG_ON(dmabuf == NULL); + dprintk(SAA716x_DEBUG, 1, "SG allocate"); + + if ((size % SAA716x_PAGE_SIZE) != 0) /* calculate required pages */ + pages = size / SAA716x_PAGE_SIZE + 1; + else + pages = size / SAA716x_PAGE_SIZE; + + /* Allocate memory for SG list */ + dmabuf->sg_list = kzalloc(sizeof (struct scatterlist) * pages, GFP_KERNEL); + if (dmabuf->sg_list == NULL) { + dprintk(SAA716x_ERROR, 1, "Failed to allocate memory for scatterlist."); + return -ENOMEM; + } + + dprintk(SAA716x_DEBUG, 1, "Initializing SG table"); + sg_init_table(dmabuf->sg_list, pages); + + if (buf == NULL) { + + /* allocate memory, unaligned */ + dmabuf->mem_virt_noalign = vmalloc((pages + 1) * SAA716x_PAGE_SIZE); + if (dmabuf->mem_virt_noalign == NULL) { + dprintk(SAA716x_ERROR, 1, "Failed to allocate memory for buffer"); + return -ENOMEM; + } + + /* align memory to page */ + dmabuf->mem_virt = (void *) PAGE_ALIGN (((unsigned long) dmabuf->mem_virt_noalign)); + + BUG_ON(!((((unsigned long) dmabuf->mem_virt) % SAA716x_PAGE_SIZE) == 0)); + } else { + dmabuf->mem_virt = buf; + } + + dmabuf->list_len = pages; /* scatterlist length */ + list = dmabuf->sg_list; + + dprintk(SAA716x_DEBUG, 1, "Allocating SG pages"); + for (i = 0; i < pages; i++) { + if (buf == NULL) + pg = vmalloc_to_page(dmabuf->mem_virt + i * SAA716x_PAGE_SIZE); + else + pg = virt_to_page(dmabuf->mem_virt + i * SAA716x_PAGE_SIZE); + + BUG_ON(pg == NULL); + sg_set_page(&list[i], pg, SAA716x_PAGE_SIZE, 0); + } + + dprintk(SAA716x_DEBUG, 1, "Done!"); + return 0; +} + +/* Fill the "page table" page with the pointers to the specified SG buffer */ +static void saa716x_dmabuf_sgpagefill(struct saa716x_dmabuf *dmabuf, struct scatterlist *sg_list, int pages, int offset) +{ + struct saa716x_dev *saa716x = dmabuf->saa716x; + struct pci_dev *pdev = saa716x->pdev; + struct scatterlist *sg_cur; + + u32 *page; + int i, j, k = 0; + dma_addr_t addr = 0; + + BUG_ON(dmabuf == NULL); + BUG_ON(sg_list == NULL); + BUG_ON(pages == 0); + dprintk(SAA716x_DEBUG, 1, "SG page fill"); + + /* make page writable for the PC */ + dma_sync_single_for_cpu(&pdev->dev, dmabuf->mem_ptab_phys, SAA716x_PAGE_SIZE, DMA_TO_DEVICE); + page = dmabuf->mem_ptab_virt; + + /* create page table */ + for (i = 0; i < pages; i++) { + sg_cur = &sg_list[i]; + BUG_ON(!(((sg_cur->length + sg_cur->offset) % SAA716x_PAGE_SIZE) == 0)); + + if (i == 0) + dmabuf->offset = (sg_cur->length + sg_cur->offset) % SAA716x_PAGE_SIZE; + else + BUG_ON(sg_cur->offset != 0); + + for (j = 0; (j * SAA716x_PAGE_SIZE) < sg_dma_len(sg_cur); j++) { + + if ((offset + sg_cur->offset) >= SAA716x_PAGE_SIZE) { + offset -= SAA716x_PAGE_SIZE; + continue; + } + + addr = ((u64)sg_dma_address(sg_cur)) + (j * SAA716x_PAGE_SIZE) - sg_cur->offset; + + BUG_ON(addr == 0); + page[k * 2] = (u32 )addr; /* Low */ + page[k * 2 + 1] = (u32 )(((u64) addr) >> 32); /* High */ + BUG_ON(page[k * 2] % SAA716x_PAGE_SIZE); + k++; + } + } + + for (; k < (SAA716x_PAGE_SIZE / 8); k++) { + page[k * 2] = (u32 ) addr; + page[k * 2 + 1] = (u32 ) (((u64 ) addr) >> 32); + } + + /* make "page table" page writable for the PC */ + dma_sync_single_for_device(&pdev->dev, + dmabuf->mem_ptab_phys, + SAA716x_PAGE_SIZE, + DMA_TO_DEVICE); + +} + +void saa716x_dmabufsync_dev(struct saa716x_dmabuf *dmabuf) +{ + struct saa716x_dev *saa716x = dmabuf->saa716x; + struct pci_dev *pdev = saa716x->pdev; + + dprintk(SAA716x_DEBUG, 1, "DMABUF sync DEVICE"); + BUG_ON(dmabuf->sg_list == NULL); + + dma_sync_sg_for_device(&pdev->dev, + dmabuf->sg_list, + dmabuf->list_len, + DMA_FROM_DEVICE); + +} + +void saa716x_dmabufsync_cpu(struct saa716x_dmabuf *dmabuf) +{ + struct saa716x_dev *saa716x = dmabuf->saa716x; + struct pci_dev *pdev = saa716x->pdev; + + dprintk(SAA716x_DEBUG, 1, "DMABUF sync CPU"); + BUG_ON(dmabuf->sg_list == NULL); + + dma_sync_sg_for_cpu(&pdev->dev, + dmabuf->sg_list, + dmabuf->list_len, + DMA_FROM_DEVICE); +} + +/* Allocates a DMA buffer for the specified external linear buffer. */ +int saa716x_dmabuf_alloc(struct saa716x_dev *saa716x, struct saa716x_dmabuf *dmabuf, int size) +{ + struct pci_dev *pdev = saa716x->pdev; + + int ret; + + BUG_ON(saa716x == NULL); + BUG_ON(dmabuf == NULL); + BUG_ON(! (size > 0)); + + dmabuf->dma_type = SAA716x_DMABUF_INT; + + dmabuf->mem_virt_noalign = NULL; + dmabuf->mem_virt = NULL; + dmabuf->mem_ptab_phys = 0; + dmabuf->mem_ptab_virt = NULL; + + dmabuf->list_len = 0; + dmabuf->saa716x = saa716x; + + /* Allocate page table */ + ret = saa716x_allocate_ptable(dmabuf); + if (ret < 0) { + dprintk(SAA716x_ERROR, 1, "PT alloc failed, Out of memory"); + goto err1; + } + + /* Allocate buffer as SG */ + ret = saa716x_dmabuf_sgalloc(dmabuf, NULL, size); + if (ret < 0) { + dprintk(SAA716x_ERROR, 1, "SG alloc failed"); + goto err2; + } + + ret = dma_map_sg(&pdev->dev, dmabuf->sg_list, dmabuf->list_len, DMA_FROM_DEVICE); + if (ret < 0) { + dprintk(SAA716x_ERROR, 1, "SG map failed"); + goto err3; + } + + saa716x_dmabuf_sgpagefill(dmabuf, dmabuf->sg_list, ret, 0); + + return 0; +err3: + saa716x_dmabuf_sgfree(dmabuf); +err2: + saa716x_free_ptable(dmabuf); +err1: + return ret; +} + +void saa716x_dmabuf_free(struct saa716x_dev *saa716x, struct saa716x_dmabuf *dmabuf) +{ + struct pci_dev *pdev = saa716x->pdev; + + BUG_ON(saa716x == NULL); + BUG_ON(dmabuf == NULL); + + dma_unmap_sg(&pdev->dev, dmabuf->sg_list, dmabuf->list_len, DMA_FROM_DEVICE); + saa716x_dmabuf_sgfree(dmabuf); + saa716x_free_ptable(dmabuf); +} diff --git a/drivers/media/common/saa716x/saa716x_dma.h b/drivers/media/common/saa716x/saa716x_dma.h new file mode 100644 index 0000000..f92d667 --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_dma.h @@ -0,0 +1,38 @@ +#ifndef __SAA716x_DMA_H +#define __SAA716x_DMA_H + +#define SAA716x_PAGE_SIZE 4096 + +enum saa716x_dma_type { + SAA716x_DMABUF_EXT_LIN, /* Linear external */ + SAA716x_DMABUF_EXT_SG, /* SG external */ + SAA716x_DMABUF_INT /* Linear internal */ +}; + +struct saa716x_dev; + +struct saa716x_dmabuf { + enum saa716x_dma_type dma_type; + + void *mem_virt_noalign; + void *mem_virt; /* page aligned */ + dma_addr_t mem_ptab_phys; + void *mem_ptab_virt; + void *sg_list; /* SG list */ + + struct saa716x_dev *saa716x; + + int list_len; /* buffer len */ + int offset; /* page offset */ +}; + +extern int saa716x_dmabuf_alloc(struct saa716x_dev *saa716x, + struct saa716x_dmabuf *dmabuf, + int size); +extern void saa716x_dmabuf_free(struct saa716x_dev *saa716x, + struct saa716x_dmabuf *dmabuf); + +extern void saa716x_dmabufsync_dev(struct saa716x_dmabuf *dmabuf); +extern void saa716x_dmabufsync_cpu(struct saa716x_dmabuf *dmabuf); + +#endif /* __SAA716x_DMA_H */ diff --git a/drivers/media/common/saa716x/saa716x_dma_reg.h b/drivers/media/common/saa716x/saa716x_dma_reg.h new file mode 100644 index 0000000..6037ca9 --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_dma_reg.h @@ -0,0 +1,200 @@ +#ifndef __SAA716x_DMA_REG_H +#define __SAA716x_DMA_REG_H + +/* -------------- BAM Registers -------------- */ + +#define BAM_VI0_0_DMA_BUF_MODE 0x000 + +#define BAM_VI0_0_ADDR_OFFST_0 0x004 +#define BAM_VI0_0_ADDR_OFFST_1 0x008 +#define BAM_VI0_0_ADDR_OFFST_2 0x00c +#define BAM_VI0_0_ADDR_OFFST_3 0x010 +#define BAM_VI0_0_ADDR_OFFST_4 0x014 +#define BAM_VI0_0_ADDR_OFFST_5 0x018 +#define BAM_VI0_0_ADDR_OFFST_6 0x01c +#define BAM_VI0_0_ADDR_OFFST_7 0x020 + +#define BAM_VI0_1_DMA_BUF_MODE 0x024 +#define BAM_VI0_1_ADDR_OFFST_0 0x028 +#define BAM_VI0_1_ADDR_OFFST_1 0x02c +#define BAM_VI0_1_ADDR_OFFST_2 0x030 +#define BAM_VI0_1_ADDR_OFFST_3 0x034 +#define BAM_VI0_1_ADDR_OFFST_4 0x038 +#define BAM_VI0_1_ADDR_OFFST_5 0x03c +#define BAM_VI0_1_ADDR_OFFST_6 0x040 +#define BAM_VI0_1_ADDR_OFFST_7 0x044 + +#define BAM_VI0_2_DMA_BUF_MODE 0x048 +#define BAM_VI0_2_ADDR_OFFST_0 0x04c +#define BAM_VI0_2_ADDR_OFFST_1 0x050 +#define BAM_VI0_2_ADDR_OFFST_2 0x054 +#define BAM_VI0_2_ADDR_OFFST_3 0x058 +#define BAM_VI0_2_ADDR_OFFST_4 0x05c +#define BAM_VI0_2_ADDR_OFFST_5 0x060 +#define BAM_VI0_2_ADDR_OFFST_6 0x064 +#define BAM_VI0_2_ADDR_OFFST_7 0x068 + + +#define BAM_VI1_0_DMA_BUF_MODE 0x06c +#define BAM_VI1_0_ADDR_OFFST_0 0x070 +#define BAM_VI1_0_ADDR_OFFST_1 0x074 +#define BAM_VI1_0_ADDR_OFFST_2 0x078 +#define BAM_VI1_0_ADDR_OFFST_3 0x07c +#define BAM_VI1_0_ADDR_OFFST_4 0x080 +#define BAM_VI1_0_ADDR_OFFST_5 0x084 +#define BAM_VI1_0_ADDR_OFFST_6 0x088 +#define BAM_VI1_0_ADDR_OFFST_7 0x08c + +#define BAM_VI1_1_DMA_BUF_MODE 0x090 +#define BAM_VI1_1_ADDR_OFFST_0 0x094 +#define BAM_VI1_1_ADDR_OFFST_1 0x098 +#define BAM_VI1_1_ADDR_OFFST_2 0x09c +#define BAM_VI1_1_ADDR_OFFST_3 0x0a0 +#define BAM_VI1_1_ADDR_OFFST_4 0x0a4 +#define BAM_VI1_1_ADDR_OFFST_5 0x0a8 +#define BAM_VI1_1_ADDR_OFFST_6 0x0ac +#define BAM_VI1_1_ADDR_OFFST_7 0x0b0 + +#define BAM_VI1_2_DMA_BUF_MODE 0x0b4 +#define BAM_VI1_2_ADDR_OFFST_0 0x0b8 +#define BAM_VI1_2_ADDR_OFFST_1 0x0bc +#define BAM_VI1_2_ADDR_OFFST_2 0x0c0 +#define BAM_VI1_2_ADDR_OFFST_3 0x0c4 +#define BAM_VI1_2_ADDR_OFFST_4 0x0c8 +#define BAM_VI1_2_ADDR_OFFST_5 0x0cc +#define BAM_VI1_2_ADDR_OFFST_6 0x0d0 +#define BAM_VI1_2_ADDR_OFFST_7 0x0d4 + + +#define BAM_FGPI0_DMA_BUF_MODE 0x0d8 +#define BAM_FGPI0_ADDR_OFFST_0 0x0dc +#define BAM_FGPI0_ADDR_OFFST_1 0x0e0 +#define BAM_FGPI0_ADDR_OFFST_2 0x0e4 +#define BAM_FGPI0_ADDR_OFFST_3 0x0e8 +#define BAM_FGPI0_ADDR_OFFST_4 0x0ec +#define BAM_FGPI0_ADDR_OFFST_5 0x0f0 +#define BAM_FGPI0_ADDR_OFFST_6 0x0f4 +#define BAM_FGPI0_ADDR_OFFST_7 0x0f8 + +#define BAM_FGPI1_DMA_BUF_MODE 0x0fc +#define BAM_FGPI1_ADDR_OFFST_0 0x100 +#define BAM_FGPI1_ADDR_OFFST_1 0x104 +#define BAM_FGPI1_ADDR_OFFST_2 0x108 +#define BAM_FGPI1_ADDR_OFFST_3 0x10c +#define BAM_FGPI1_ADDR_OFFST_4 0x110 +#define BAM_FGPI1_ADDR_OFFST_5 0x114 +#define BAM_FGPI1_ADDR_OFFST_6 0x118 +#define BAM_FGPI1_ADDR_OFFST_7 0x11c + +#define BAM_FGPI2_DMA_BUF_MODE 0x120 +#define BAM_FGPI2_ADDR_OFFST_0 0x124 +#define BAM_FGPI2_ADDR_OFFST_1 0x128 +#define BAM_FGPI2_ADDR_OFFST_2 0x12c +#define BAM_FGPI2_ADDR_OFFST_3 0x130 +#define BAM_FGPI2_ADDR_OFFST_4 0x134 +#define BAM_FGPI2_ADDR_OFFST_5 0x138 +#define BAM_FGPI2_ADDR_OFFST_6 0x13c +#define BAM_FGPI2_ADDR_OFFST_7 0x140 + +#define BAM_FGPI3_DMA_BUF_MODE 0x144 +#define BAM_FGPI3_ADDR_OFFST_0 0x148 +#define BAM_FGPI3_ADDR_OFFST_1 0x14c +#define BAM_FGPI3_ADDR_OFFST_2 0x150 +#define BAM_FGPI3_ADDR_OFFST_3 0x154 +#define BAM_FGPI3_ADDR_OFFST_4 0x158 +#define BAM_FGPI3_ADDR_OFFST_5 0x15c +#define BAM_FGPI3_ADDR_OFFST_6 0x160 +#define BAM_FGPI3_ADDR_OFFST_7 0x164 + + +#define BAM_AI0_DMA_BUF_MODE 0x168 +#define BAM_AI0_ADDR_OFFST_0 0x16c +#define BAM_AI0_ADDR_OFFST_1 0x170 +#define BAM_AI0_ADDR_OFFST_2 0x174 +#define BAM_AI0_ADDR_OFFST_3 0x178 +#define BAM_AI0_ADDR_OFFST_4 0x17c +#define BAM_AIO_ADDR_OFFST_5 0x180 +#define BAM_AI0_ADDR_OFFST_6 0x184 +#define BAM_AIO_ADDR_OFFST_7 0x188 + +#define BAM_AI1_DMA_BUF_MODE 0x18c +#define BAM_AI1_ADDR_OFFST_0 0x190 +#define BAM_AI1_ADDR_OFFST_1 0x194 +#define BAM_AI1_ADDR_OFFST_2 0x198 +#define BAM_AI1_ADDR_OFFST_3 0x19c +#define BAM_AI1_ADDR_OFFST_4 0x1a0 +#define BAM_AI1_ADDR_OFFST_5 0x1a4 +#define BAM_AI1_ADDR_OFFST_6 0x1a8 +#define BAM_AI1_ADDR_OFFST_7 0x1ac + +#define BAM_SW_RST 0xff0 +#define BAM_SW_RESET (0x00000001 << 0) + + + + + +/* -------------- MMU Registers -------------- */ + +#define MMU_MODE 0x000 + +#define MMU_DMA_CONFIG0 0x004 +#define MMU_DMA_CONFIG1 0x008 +#define MMU_DMA_CONFIG2 0x00c +#define MMU_DMA_CONFIG3 0x010 +#define MMU_DMA_CONFIG4 0x014 +#define MMU_DMA_CONFIG5 0x018 +#define MMU_DMA_CONFIG6 0x01c +#define MMU_DMA_CONFIG7 0x020 +#define MMU_DMA_CONFIG8 0x024 +#define MMU_DMA_CONFIG9 0x028 +#define MMU_DMA_CONFIG10 0x02c +#define MMU_DMA_CONFIG11 0x030 +#define MMU_DMA_CONFIG12 0x034 +#define MMU_DMA_CONFIG13 0x038 +#define MMU_DMA_CONFIG14 0x03c +#define MMU_DMA_CONFIG15 0x040 + +#define MMU_SW_RST 0xff0 +#define MMU_SW_RESET (0x0001 << 0) + +#define MMU_PTA_BASE0 0x044 /* DMA 0 */ +#define MMU_PTA_BASE1 0x084 /* DMA 1 */ +#define MMU_PTA_BASE2 0x0c4 /* DMA 2 */ +#define MMU_PTA_BASE3 0x104 /* DMA 3 */ +#define MMU_PTA_BASE4 0x144 /* DMA 4 */ +#define MMU_PTA_BASE5 0x184 /* DMA 5 */ +#define MMU_PTA_BASE6 0x1c4 /* DMA 6 */ +#define MMU_PTA_BASE7 0x204 /* DMA 7 */ +#define MMU_PTA_BASE8 0x244 /* DMA 8 */ +#define MMU_PTA_BASE9 0x284 /* DMA 9 */ +#define MMU_PTA_BASE10 0x2c4 /* DMA 10 */ +#define MMU_PTA_BASE11 0x304 /* DMA 11 */ +#define MMU_PTA_BASE12 0x344 /* DMA 12 */ +#define MMU_PTA_BASE13 0x384 /* DMA 13 */ +#define MMU_PTA_BASE14 0x3c4 /* DMA 14 */ +#define MMU_PTA_BASE15 0x404 /* DMA 15 */ + +#define MMU_PTA_BASE 0x044 /* DMA 0 */ +#define MMU_PTA_OFFSET 0x40 + +#define PTA_BASE(__ch) (MMU_PTA_BASE + (MMU_PTA_OFFSET * __ch)) + +#define MMU_PTA0_LSB(__ch) PTA_BASE(__ch) + 0x00 +#define MMU_PTA0_MSB(__ch) PTA_BASE(__ch) + 0x04 +#define MMU_PTA1_LSB(__ch) PTA_BASE(__ch) + 0x08 +#define MMU_PTA1_MSB(__ch) PTA_BASE(__ch) + 0x0c +#define MMU_PTA2_LSB(__ch) PTA_BASE(__ch) + 0x10 +#define MMU_PTA2_MSB(__ch) PTA_BASE(__ch) + 0x14 +#define MMU_PTA3_LSB(__ch) PTA_BASE(__ch) + 0x18 +#define MMU_PTA3_MSB(__ch) PTA_BASE(__ch) + 0x1c +#define MMU_PTA4_LSB(__ch) PTA_BASE(__ch) + 0x20 +#define MMU_PTA4_MSB(__ch) PTA_BASE(__ch) + 0x24 +#define MMU_PTA5_LSB(__ch) PTA_BASE(__ch) + 0x28 +#define MMU_PTA5_MSB(__ch) PTA_BASE(__ch) + 0x2c +#define MMU_PTA6_LSB(__ch) PTA_BASE(__ch) + 0x30 +#define MMU_PTA6_MSB(__ch) PTA_BASE(__ch) + 0x34 +#define MMU_PTA7_LSB(__ch) PTA_BASE(__ch) + 0x38 +#define MMU_PTA7_MSB(__ch) PTA_BASE(__ch) + 0x3c + +#endif /* __SAA716x_DMA_REG_H */ diff --git a/drivers/media/common/saa716x/saa716x_ff.h b/drivers/media/common/saa716x/saa716x_ff.h new file mode 100644 index 0000000..cb65929 --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_ff.h @@ -0,0 +1,158 @@ +#ifndef __SAA716x_FF_H +#define __SAA716x_FF_H + +#include "dvb_filter.h" +#include "dvb_ringbuffer.h" + +#define TECHNOTREND 0x13c2 +#define S2_6400_DUAL_S2_PREMIUM_DEVEL 0x3009 +#define S2_6400_DUAL_S2_PREMIUM_PROD 0x300A + +#define TT_PREMIUM_GPIO_POWER_ENABLE 27 +#define TT_PREMIUM_GPIO_RESET_BACKEND 26 +#define TT_PREMIUM_GPIO_FPGA_CS1 17 +#define TT_PREMIUM_GPIO_FPGA_CS0 16 +#define TT_PREMIUM_GPIO_FPGA_PROGRAMN 15 +#define TT_PREMIUM_GPIO_FPGA_DONE 14 +#define TT_PREMIUM_GPIO_FPGA_INITN 13 + +/* fpga interrupt register addresses */ +#define FPGA_ADDR_PHI_ICTRL 0x8000 /* PHI General control of the PC => STB interrupt controller */ +#define FPGA_ADDR_PHI_ISR 0x8010 /* PHI Interrupt Status Register */ +#define FPGA_ADDR_PHI_ISET 0x8020 /* PHI Interrupt Set Register */ +#define FPGA_ADDR_PHI_ICLR 0x8030 /* PHI Interrupt Clear Register */ +#define FPGA_ADDR_EMI_ICTRL 0x8100 /* EMI General control of the STB => PC interrupt controller */ +#define FPGA_ADDR_EMI_ISR 0x8110 /* EMI Interrupt Status Register */ +#define FPGA_ADDR_EMI_ISET 0x8120 /* EMI Interrupt Set Register */ +#define FPGA_ADDR_EMI_ICLR 0x8130 /* EMI Interrupt Clear Register */ + +/* fpga TS router register addresses */ +#define FPGA_ADDR_TSR_CTRL 0x8200 /* TS router control register */ +#define FPGA_ADDR_TSR_MUX1 0x8210 /* TS multiplexer 1 selection register */ +#define FPGA_ADDR_TSR_MUX2 0x8220 /* TS multiplexer 2 selection register */ +#define FPGA_ADDR_TSR_MUX3 0x8230 /* TS multiplexer 3 selection register */ +#define FPGA_ADDR_TSR_MUXCI1 0x8240 /* TS multiplexer CI 1 selection register */ +#define FPGA_ADDR_TSR_MUXCI2 0x8250 /* TS multiplexer CI 2 selection register */ + +#define FPGA_ADDR_TSR_BRFE1 0x8280 /* bit rate for TS coming from frontend 1 */ +#define FPGA_ADDR_TSR_BRFE2 0x8284 /* bit rate for TS coming from frontend 2 */ +#define FPGA_ADDR_TSR_BRFF1 0x828C /* bit rate for TS coming from FIFO 1 */ +#define FPGA_ADDR_TSR_BRO1 0x8294 /* bit rate for TS going to output 1 */ +#define FPGA_ADDR_TSR_BRO2 0x8298 /* bit rate for TS going to output 2 */ +#define FPGA_ADDR_TSR_BRO3 0x829C /* bit rate for TS going to output 3 */ + +/* fpga TS FIFO register addresses */ +#define FPGA_ADDR_FIFO_CTRL 0x8300 /* FIFO control register */ +#define FPGA_ADDR_FIFO_STAT 0x8310 /* FIFO status register */ + +#define FPGA_ADDR_VERSION 0x80F0 /* FPGA bitstream version register */ + +#define FPGA_ADDR_PIO_CTRL 0x8500 /* FPGA GPIO control register */ + +#define ISR_CMD_MASK 0x0001 /* interrupt source for normal cmds (osd, fre, av, ...) */ +#define ISR_READY_MASK 0x0002 /* interrupt source for command acknowledge */ +#define ISR_BLOCK_MASK 0x0004 /* interrupt source for single block transfers and acknowledge */ +#define ISR_DATA_MASK 0x0008 /* interrupt source for data transfer acknowledge */ +#define ISR_BOOT_FINISH_MASK 0x0010 /* interrupt source for boot finish indication */ +#define ISR_AUDIO_PTS_MASK 0x0020 /* interrupt source for audio PTS */ +#define ISR_VIDEO_PTS_MASK 0x0040 /* interrupt source for video PTS */ +#define ISR_CURRENT_STC_MASK 0x0080 /* interrupt source for current system clock */ +#define ISR_REMOTE_EVENT_MASK 0x0100 /* interrupt source for remote events */ +#define ISR_DVO_FORMAT_MASK 0x0200 /* interrupt source for DVO format change */ +#define ISR_OSD_CMD_MASK 0x0400 /* interrupt source for OSD cmds */ +#define ISR_OSD_READY_MASK 0x0800 /* interrupt source for OSD command acknowledge */ +#define ISR_FE_CMD_MASK 0x1000 /* interrupt source for frontend cmds */ +#define ISR_FE_READY_MASK 0x2000 /* interrupt source for frontend command acknowledge */ +#define ISR_LOG_MESSAGE_MASK 0x4000 /* interrupt source for log messages */ +#define ISR_FIFO1_EMPTY_MASK 0x8000 /* interrupt source for FIFO1 empty */ + +#define ADDR_CMD_DATA 0x0000 /* address for cmd data in fpga dpram */ +#define ADDR_OSD_CMD_DATA 0x01A0 /* address for OSD cmd data */ +#define ADDR_FE_CMD_DATA 0x05C0 /* address for frontend cmd data */ +#define ADDR_BLOCK_DATA 0x0600 /* address for block data */ +#define ADDR_AUDIO_PTS 0x3E00 /* address for audio PTS (64 Bits) */ +#define ADDR_VIDEO_PTS 0x3E08 /* address for video PTS (64 Bits) */ +#define ADDR_CURRENT_STC 0x3E10 /* address for system clock (64 Bits) */ +#define ADDR_DVO_FORMAT 0x3E18 /* address for DVO format 32 Bits) */ +#define ADDR_REMOTE_EVENT 0x3F00 /* address for remote events (32 Bits) */ +#define ADDR_LOG_MESSAGE 0x3F80 /* address for log messages */ + +#define SIZE_CMD_DATA 0x01A0 /* maximum size for command data (416 Bytes) */ +#define SIZE_OSD_CMD_DATA 0x0420 /* maximum size for OSD command data (1056 Bytes) */ +#define SIZE_FE_CMD_DATA 0x0040 /* maximum size for frontend command data (64 Bytes) */ +#define SIZE_BLOCK_DATA 0x3800 /* maximum size for block data (14 kB) */ +#define SIZE_LOG_MESSAGE_DATA 0x0080 /* maximum size for log message data (128 Bytes) */ + +#define SIZE_BLOCK_HEADER 8 /* block header size */ + +#define MAX_RESULT_LEN 256 +#define MAX_DATA_LEN (1024 * 1024) + +#define TSOUT_LEN (1024 * TS_SIZE) +#define TSBUF_LEN (8 * 1024) + +/* place to store all the necessary device information */ +struct sti7109_dev { + struct saa716x_dev *dev; + struct dvb_device *osd_dev; + struct dvb_device *video_dev; + struct dvb_device *audio_dev; + + void *iobuf; /* memory for all buffers */ + struct dvb_ringbuffer tsout; /* buffer for TS output */ + u8 *tsbuf; /* temp ts buffer */ + + struct tasklet_struct fifo_tasklet; + + wait_queue_head_t boot_finish_wq; + int boot_finished; + + wait_queue_head_t cmd_ready_wq; + int cmd_ready; + u8 cmd_data[SIZE_CMD_DATA]; + u32 cmd_len; + + wait_queue_head_t result_avail_wq; + int result_avail; + u8 result_data[MAX_RESULT_LEN]; + u32 result_len; + u32 result_max_len; + + wait_queue_head_t osd_cmd_ready_wq; + int osd_cmd_ready; + u8 osd_cmd_data[SIZE_OSD_CMD_DATA]; + u32 osd_cmd_len; + + wait_queue_head_t osd_result_avail_wq; + int osd_result_avail; + u8 osd_result_data[MAX_RESULT_LEN]; + u32 osd_result_len; + u32 osd_result_max_len; + + u16 data_handle; + u8 *data_buffer; /* raw data transfer buffer */ + wait_queue_head_t data_ready_wq; + int data_ready; + wait_queue_head_t block_done_wq; + int block_done; + + struct mutex cmd_lock; + struct mutex osd_cmd_lock; + struct mutex data_lock; + + u64 audio_pts; + u64 video_pts; + u64 current_stc; + + u32 int_count_enable; + u32 total_int_count; + u32 fgpi_int_count[2]; + u32 i2c_int_count[2]; + u32 ext_int_total_count; + u32 ext_int_source_count[16]; + u32 last_int_ticks; + + u16 fpga_version; +}; + +#endif /* __SAA716x_FF_H */ diff --git a/drivers/media/common/saa716x/saa716x_ff_cmd.c b/drivers/media/common/saa716x/saa716x_ff_cmd.c new file mode 100644 index 0000000..81c1078 --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_ff_cmd.c @@ -0,0 +1,412 @@ +#include + +#include +#include + +#include "saa716x_phi_reg.h" + +#include "saa716x_phi.h" +#include "saa716x_spi.h" +#include "saa716x_priv.h" +#include "saa716x_ff.h" +#include "saa716x_ff_cmd.h" + + +int sti7109_cmd_init(struct sti7109_dev *sti7109) +{ + mutex_init(&sti7109->cmd_lock); + mutex_init(&sti7109->osd_cmd_lock); + mutex_init(&sti7109->data_lock); + + init_waitqueue_head(&sti7109->boot_finish_wq); + sti7109->boot_finished = 0; + + init_waitqueue_head(&sti7109->cmd_ready_wq); + sti7109->cmd_ready = 0; + + init_waitqueue_head(&sti7109->result_avail_wq); + sti7109->result_avail = 0; + + init_waitqueue_head(&sti7109->osd_cmd_ready_wq); + sti7109->osd_cmd_ready = 0; + init_waitqueue_head(&sti7109->osd_result_avail_wq); + sti7109->osd_result_avail = 0; + + sti7109->data_handle = 0; + sti7109->data_buffer = (u8 *) (sti7109->iobuf + TSOUT_LEN + TSBUF_LEN); + init_waitqueue_head(&sti7109->data_ready_wq); + sti7109->data_ready = 0; + init_waitqueue_head(&sti7109->block_done_wq); + sti7109->block_done = 0; + return 0; +} + +static int sti7109_do_raw_cmd(struct sti7109_dev * sti7109) +{ + struct saa716x_dev * saa716x = sti7109->dev; + unsigned long timeout; + + timeout = 1 * HZ; + timeout = wait_event_interruptible_timeout(sti7109->cmd_ready_wq, + sti7109->cmd_ready == 1, + timeout); + + if (timeout == -ERESTARTSYS || sti7109->cmd_ready == 0) { + if (timeout == -ERESTARTSYS) { + /* a signal arrived */ + dprintk(SAA716x_ERROR, 1, "cmd ERESTARTSYS"); + return -ERESTARTSYS; + } + dprintk(SAA716x_ERROR, 1, + "timed out waiting for command ready"); + return -EIO; + } + + sti7109->cmd_ready = 0; + sti7109->result_avail = 0; + saa716x_phi_write(saa716x, ADDR_CMD_DATA, sti7109->cmd_data, + sti7109->cmd_len); + SAA716x_EPWR(PHI_1, FPGA_ADDR_PHI_ISET, ISR_CMD_MASK); + + if (sti7109->result_max_len > 0) { + timeout = 1 * HZ; + timeout = wait_event_interruptible_timeout( + sti7109->result_avail_wq, + sti7109->result_avail == 1, + timeout); + + if (timeout == -ERESTARTSYS || sti7109->result_avail == 0) { + sti7109->result_len = 0; + if (timeout == -ERESTARTSYS) { + /* a signal arrived */ + dprintk(SAA716x_ERROR, 1, "result ERESTARTSYS"); + return -ERESTARTSYS; + } + dprintk(SAA716x_ERROR, 1, + "timed out waiting for command result"); + return -EIO; + } + + if (sti7109->result_len > sti7109->result_max_len) { + sti7109->result_len = sti7109->result_max_len; + dprintk(SAA716x_NOTICE, 1, + "not enough space in result buffer"); + } + } + + return 0; +} + +int sti7109_raw_cmd(struct sti7109_dev * sti7109, osd_raw_cmd_t * cmd) +{ + struct saa716x_dev * saa716x = sti7109->dev; + int err; + + if (cmd->cmd_len > SIZE_CMD_DATA) { + dprintk(SAA716x_ERROR, 1, "command too long"); + return -EFAULT; + } + + mutex_lock(&sti7109->cmd_lock); + + err = -EFAULT; + if (copy_from_user(sti7109->cmd_data, (void __user *)cmd->cmd_data, + cmd->cmd_len)) + goto out; + + sti7109->cmd_len = cmd->cmd_len; + sti7109->result_max_len = cmd->result_len; + + err = sti7109_do_raw_cmd(sti7109); + if (err) + goto out; + + cmd->result_len = sti7109->result_len; + if (sti7109->result_len > 0) { + if (copy_to_user((void __user *)cmd->result_data, + sti7109->result_data, + sti7109->result_len)) + err = -EFAULT; + } + +out: + mutex_unlock(&sti7109->cmd_lock); + return err; +} + +static int sti7109_do_raw_osd_cmd(struct sti7109_dev * sti7109) +{ + struct saa716x_dev * saa716x = sti7109->dev; + unsigned long timeout; + + timeout = 1 * HZ; + timeout = wait_event_interruptible_timeout(sti7109->osd_cmd_ready_wq, + sti7109->osd_cmd_ready == 1, + timeout); + + if (timeout == -ERESTARTSYS || sti7109->osd_cmd_ready == 0) { + if (timeout == -ERESTARTSYS) { + /* a signal arrived */ + dprintk(SAA716x_ERROR, 1, "osd cmd ERESTARTSYS"); + return -ERESTARTSYS; + } + dprintk(SAA716x_ERROR, 1, + "timed out waiting for osd command ready"); + return -EIO; + } + + sti7109->osd_cmd_ready = 0; + sti7109->osd_result_avail = 0; + saa716x_phi_write(saa716x, ADDR_OSD_CMD_DATA, sti7109->osd_cmd_data, + sti7109->osd_cmd_len); + SAA716x_EPWR(PHI_1, FPGA_ADDR_PHI_ISET, ISR_OSD_CMD_MASK); + + if (sti7109->osd_result_max_len > 0) { + timeout = 1 * HZ; + timeout = wait_event_interruptible_timeout( + sti7109->osd_result_avail_wq, + sti7109->osd_result_avail == 1, + timeout); + + if (timeout == -ERESTARTSYS || sti7109->osd_result_avail == 0) { + sti7109->osd_result_len = 0; + if (timeout == -ERESTARTSYS) { + /* a signal arrived */ + dprintk(SAA716x_ERROR, 1, + "osd result ERESTARTSYS"); + return -ERESTARTSYS; + } + dprintk(SAA716x_ERROR, 1, + "timed out waiting for osd command result"); + return -EIO; + } + + if (sti7109->osd_result_len > sti7109->osd_result_max_len) { + sti7109->osd_result_len = sti7109->osd_result_max_len; + dprintk(SAA716x_NOTICE, 1, + "not enough space in result buffer"); + } + } + + return 0; +} + +int sti7109_raw_osd_cmd(struct sti7109_dev * sti7109, osd_raw_cmd_t * cmd) +{ + struct saa716x_dev * saa716x = sti7109->dev; + int err; + + if (cmd->cmd_len > SIZE_OSD_CMD_DATA) { + dprintk(SAA716x_ERROR, 1, "command too long"); + return -EFAULT; + } + + mutex_lock(&sti7109->osd_cmd_lock); + + err = -EFAULT; + if (copy_from_user(sti7109->osd_cmd_data, (void __user *)cmd->cmd_data, + cmd->cmd_len)) + goto out; + + sti7109->osd_cmd_len = cmd->cmd_len; + sti7109->osd_result_max_len = cmd->result_len; + + err = sti7109_do_raw_osd_cmd(sti7109); + if (err) + goto out; + + cmd->result_len = sti7109->osd_result_len; + if (sti7109->osd_result_len > 0) { + if (copy_to_user((void __user *)cmd->result_data, + sti7109->osd_result_data, + sti7109->osd_result_len)) + err = -EFAULT; + } + +out: + mutex_unlock(&sti7109->osd_cmd_lock); + return err; +} + +static int sti7109_do_raw_data(struct sti7109_dev * sti7109, osd_raw_data_t * data) +{ + struct saa716x_dev * saa716x = sti7109->dev; + unsigned long timeout; + u16 blockSize; + u16 lastBlockSize; + u16 numBlocks; + u16 blockIndex; + u8 blockHeader[SIZE_BLOCK_HEADER]; + u8 * blockPtr; + int activeBlock; + + timeout = 1 * HZ; + timeout = wait_event_interruptible_timeout(sti7109->data_ready_wq, + sti7109->data_ready == 1, + timeout); + + if (timeout == -ERESTARTSYS || sti7109->data_ready == 0) { + if (timeout == -ERESTARTSYS) { + /* a signal arrived */ + dprintk(SAA716x_ERROR, 1, "data ERESTARTSYS"); + return -ERESTARTSYS; + } + dprintk(SAA716x_ERROR, 1, "timed out waiting for data ready"); + return -EIO; + } + + sti7109->data_ready = 0; + + /* + * 8 bytes is the size of the block header. Block header structure is: + * 16 bit - block index + * 16 bit - number of blocks + * 16 bit - current block data size + * 16 bit - block handle. This is used to reference the data in the + * command that uses it. + */ + blockSize = (SIZE_BLOCK_DATA / 2) - SIZE_BLOCK_HEADER; + numBlocks = data->data_length / blockSize; + lastBlockSize = data->data_length % blockSize; + if (lastBlockSize > 0) + numBlocks++; + + blockHeader[2] = (u8) (numBlocks >> 8); + blockHeader[3] = (u8) numBlocks; + blockHeader[6] = (u8) (sti7109->data_handle >> 8); + blockHeader[7] = (u8) sti7109->data_handle; + blockPtr = sti7109->data_buffer; + activeBlock = 0; + for (blockIndex = 0; blockIndex < numBlocks; blockIndex++) { + u32 addr; + + if (lastBlockSize && (blockIndex == (numBlocks - 1))) + blockSize = lastBlockSize; + + blockHeader[0] = (uint8_t) (blockIndex >> 8); + blockHeader[1] = (uint8_t) blockIndex; + blockHeader[4] = (uint8_t) (blockSize >> 8); + blockHeader[5] = (uint8_t) blockSize; + + addr = ADDR_BLOCK_DATA + activeBlock * (SIZE_BLOCK_DATA / 2); + saa716x_phi_write(saa716x, addr, blockHeader, + SIZE_BLOCK_HEADER); + saa716x_phi_write(saa716x, addr + SIZE_BLOCK_HEADER, blockPtr, + blockSize); + activeBlock = (activeBlock + 1) & 1; + if (blockIndex > 0) { + timeout = 1 * HZ; + timeout = wait_event_timeout(sti7109->block_done_wq, + sti7109->block_done == 1, + timeout); + + if (sti7109->block_done == 0) { + dprintk(SAA716x_ERROR, 1, + "timed out waiting for block done"); + return -EIO; + } + } + sti7109->block_done = 0; + SAA716x_EPWR(PHI_1, FPGA_ADDR_PHI_ISET, ISR_BLOCK_MASK); + blockPtr += blockSize; + } + timeout = 1 * HZ; + timeout = wait_event_timeout(sti7109->block_done_wq, + sti7109->block_done == 1, + timeout); + + if (sti7109->block_done == 0) { + dprintk(SAA716x_ERROR, 1, "timed out waiting for block done"); + return -EIO; + } + sti7109->block_done = 0; + + data->data_handle = sti7109->data_handle; + sti7109->data_handle++; + return 0; +} + +int sti7109_raw_data(struct sti7109_dev * sti7109, osd_raw_data_t * data) +{ + struct saa716x_dev * saa716x = sti7109->dev; + int err; + + if (data->data_length > MAX_DATA_LEN) { + dprintk(SAA716x_ERROR, 1, "data too big"); + return -EFAULT; + } + + mutex_lock(&sti7109->data_lock); + + err = -EFAULT; + if (copy_from_user(sti7109->data_buffer, + (void __user *)data->data_buffer, + data->data_length)) + goto out; + + err = sti7109_do_raw_data(sti7109, data); + if (err) + goto out; + +out: + mutex_unlock(&sti7109->data_lock); + return err; +} + +int sti7109_cmd_get_fw_version(struct sti7109_dev *sti7109, u32 *fw_version) +{ + int ret_val = -EINVAL; + + mutex_lock(&sti7109->cmd_lock); + + sti7109->cmd_data[0] = 0x00; + sti7109->cmd_data[1] = 0x04; + sti7109->cmd_data[2] = 0x00; + sti7109->cmd_data[3] = 0x00; + sti7109->cmd_data[4] = 0x00; + sti7109->cmd_data[5] = 0x00; + sti7109->cmd_len = 6; + sti7109->result_max_len = MAX_RESULT_LEN; + + ret_val = sti7109_do_raw_cmd(sti7109); + if (ret_val == 0) { + *fw_version = (sti7109->result_data[6] << 16) + | (sti7109->result_data[7] << 8) + | sti7109->result_data[8]; + } + + mutex_unlock(&sti7109->cmd_lock); + + return ret_val; +} + +int sti7109_cmd_get_video_format(struct sti7109_dev *sti7109, video_size_t *vs) +{ + int ret_val = -EINVAL; + + mutex_lock(&sti7109->cmd_lock); + + sti7109->cmd_data[0] = 0x00; + sti7109->cmd_data[1] = 0x05; /* command length */ + sti7109->cmd_data[2] = 0x00; + sti7109->cmd_data[3] = 0x01; /* A/V decoder command group */ + sti7109->cmd_data[4] = 0x00; + sti7109->cmd_data[5] = 0x10; /* get video format info command */ + sti7109->cmd_data[6] = 0x00; /* decoder index 0 */ + sti7109->cmd_len = 7; + sti7109->result_max_len = MAX_RESULT_LEN; + + ret_val = sti7109_do_raw_cmd(sti7109); + if (ret_val == 0) { + vs->w = (sti7109->result_data[7] << 8) + | sti7109->result_data[8]; + vs->h = (sti7109->result_data[9] << 8) + | sti7109->result_data[10]; + vs->aspect_ratio = sti7109->result_data[11] >> 4; + } + + mutex_unlock(&sti7109->cmd_lock); + + return ret_val; +} + diff --git a/drivers/media/common/saa716x/saa716x_ff_cmd.h b/drivers/media/common/saa716x/saa716x_ff_cmd.h new file mode 100644 index 0000000..fc79f08 --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_ff_cmd.h @@ -0,0 +1,16 @@ +#ifndef __SAA716x_FF_CMD_H +#define __SAA716x_FF_CMD_H + +extern int sti7109_cmd_init(struct sti7109_dev *sti7109); +extern int sti7109_raw_cmd(struct sti7109_dev * sti7109, + osd_raw_cmd_t * cmd); +extern int sti7109_raw_osd_cmd(struct sti7109_dev * sti7109, + osd_raw_cmd_t * cmd); +extern int sti7109_raw_data(struct sti7109_dev * sti7109, + osd_raw_data_t * data); +extern int sti7109_cmd_get_fw_version(struct sti7109_dev *sti7109, + u32 *fw_version); +extern int sti7109_cmd_get_video_format(struct sti7109_dev *sti7109, + video_size_t *vs); + +#endif /* __SAA716x_FF_CMD_H */ diff --git a/drivers/media/common/saa716x/saa716x_ff_ir.c b/drivers/media/common/saa716x/saa716x_ff_ir.c new file mode 100644 index 0000000..3562478 --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_ff_ir.c @@ -0,0 +1,265 @@ +/* + * Driver for the remote control of the TT6400 DVB-S2 card + * + * Copyright (C) 2010 Oliver Endriss + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + */ + +#include +#include + +#include "saa716x_spi.h" +#include "saa716x_priv.h" +#include "saa716x_ff.h" + + +/* infrared remote control */ +struct infrared { + u16 key_map[128]; + struct input_dev *input_dev; + char input_phys[32]; + struct timer_list keyup_timer; + struct tasklet_struct tasklet; + u32 command; + u32 device_mask; + u8 protocol; + u16 last_key; + u16 last_toggle; + bool delay_timer_finished; +}; + +#define IR_RC5 0 +#define UP_TIMEOUT (HZ*7/25) + + +/* key-up timer */ +static void ir_emit_keyup(unsigned long parm) +{ + struct infrared *ir = (struct infrared *) parm; + + if (!ir || !test_bit(ir->last_key, ir->input_dev->key)) + return; + + input_report_key(ir->input_dev, ir->last_key, 0); + input_sync(ir->input_dev); +} + + +/* tasklet */ +static void ir_emit_key(unsigned long parm) +{ + struct saa716x_dev *saa716x = (struct saa716x_dev *) parm; + struct infrared *ir = saa716x->ir_priv; + u32 ircom = ir->command; + u8 data; + u8 addr; + u16 toggle; + u16 keycode; + + /* extract device address and data */ + if (ircom & 0x80000000) { /* CEC remote command */ + addr = 0; + data = ircom & 0x7F; + toggle = 0; + } else { + switch (ir->protocol) { + case IR_RC5: /* extended RC5: 5 bits device address, 7 bits data */ + addr = (ircom >> 6) & 0x1f; + /* data bits 1..6 */ + data = ircom & 0x3f; + /* data bit 7 (inverted) */ + if (!(ircom & 0x1000)) + data |= 0x40; + toggle = ircom & 0x0800; + break; + + default: + printk(KERN_ERR "%s: invalid protocol %x\n", + __func__, ir->protocol); + return; + } + } + + input_event(ir->input_dev, EV_MSC, MSC_RAW, (addr << 16) | data); + input_event(ir->input_dev, EV_MSC, MSC_SCAN, data); + + keycode = ir->key_map[data]; + + dprintk(SAA716x_DEBUG, 0, + "%s: code %08x -> addr %i data 0x%02x -> keycode %i\n", + __func__, ircom, addr, data, keycode); + + /* check device address */ + if (!(ir->device_mask & (1 << addr))) + return; + + if (!keycode) { + printk(KERN_WARNING "%s: code %08x -> addr %i data 0x%02x -> unknown key!\n", + __func__, ircom, addr, data); + return; + } + + if (timer_pending(&ir->keyup_timer)) { + del_timer(&ir->keyup_timer); + if (ir->last_key != keycode || toggle != ir->last_toggle) { + ir->delay_timer_finished = false; + input_event(ir->input_dev, EV_KEY, ir->last_key, 0); + input_event(ir->input_dev, EV_KEY, keycode, 1); + input_sync(ir->input_dev); + } else if (ir->delay_timer_finished) { + input_event(ir->input_dev, EV_KEY, keycode, 2); + input_sync(ir->input_dev); + } + } else { + ir->delay_timer_finished = false; + input_event(ir->input_dev, EV_KEY, keycode, 1); + input_sync(ir->input_dev); + } + + ir->last_key = keycode; + ir->last_toggle = toggle; + + ir->keyup_timer.expires = jiffies + UP_TIMEOUT; + add_timer(&ir->keyup_timer); + +} + + +/* register with input layer */ +static void ir_register_keys(struct infrared *ir) +{ + int i; + + set_bit(EV_KEY, ir->input_dev->evbit); + set_bit(EV_REP, ir->input_dev->evbit); + set_bit(EV_MSC, ir->input_dev->evbit); + + set_bit(MSC_RAW, ir->input_dev->mscbit); + set_bit(MSC_SCAN, ir->input_dev->mscbit); + + memset(ir->input_dev->keybit, 0, sizeof(ir->input_dev->keybit)); + + for (i = 0; i < ARRAY_SIZE(ir->key_map); i++) { + if (ir->key_map[i] > KEY_MAX) + ir->key_map[i] = 0; + else if (ir->key_map[i] > KEY_RESERVED) + set_bit(ir->key_map[i], ir->input_dev->keybit); + } + + ir->input_dev->keycode = ir->key_map; + ir->input_dev->keycodesize = sizeof(ir->key_map[0]); + ir->input_dev->keycodemax = ARRAY_SIZE(ir->key_map); +} + + +/* called by the input driver after rep[REP_DELAY] ms */ +static void ir_repeat_key(unsigned long parm) +{ + struct infrared *ir = (struct infrared *) parm; + + ir->delay_timer_finished = true; +} + + +/* interrupt handler */ +void saa716x_ir_handler(struct saa716x_dev *saa716x, u32 ir_cmd) +{ + struct infrared *ir = saa716x->ir_priv; + + if (!ir) + return; + + ir->command = ir_cmd; + tasklet_schedule(&ir->tasklet); +} + + +int saa716x_ir_init(struct saa716x_dev *saa716x) +{ + struct input_dev *input_dev; + struct infrared *ir; + int rc; + int i; + + if (!saa716x) + return -ENOMEM; + + ir = kzalloc(sizeof(struct infrared), GFP_KERNEL); + if (!ir) + return -ENOMEM; + + init_timer(&ir->keyup_timer); + ir->keyup_timer.function = ir_emit_keyup; + ir->keyup_timer.data = (unsigned long) ir; + + input_dev = input_allocate_device(); + if (!input_dev) + goto err; + + ir->input_dev = input_dev; + input_dev->name = "TT6400 DVB IR receiver"; + snprintf(ir->input_phys, sizeof(ir->input_phys), + "pci-%s/ir0", pci_name(saa716x->pdev)); + input_dev->phys = ir->input_phys; + input_dev->id.bustype = BUS_PCI; + input_dev->id.version = 1; + input_dev->id.vendor = saa716x->pdev->subsystem_vendor; + input_dev->id.product = saa716x->pdev->subsystem_device; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) + input_dev->dev.parent = &saa716x->pdev->dev; +#else + input_dev->cdev.dev = &saa716x->pdev->dev; +#endif + rc = input_register_device(input_dev); + if (rc) + goto err; + + /* TODO: fix setup/keymap */ + ir->protocol = IR_RC5; + ir->device_mask = 0xffffffff; + for (i = 0; i < ARRAY_SIZE(ir->key_map); i++) + ir->key_map[i] = i+1; + ir_register_keys(ir); + + /* override repeat timer */ + input_dev->timer.function = ir_repeat_key; + input_dev->timer.data = (unsigned long) ir; + + tasklet_init(&ir->tasklet, ir_emit_key, (unsigned long) saa716x); + saa716x->ir_priv = ir; + + return 0; + +err: + if (ir->input_dev) + input_free_device(ir->input_dev); + kfree(ir); + return -ENOMEM; +} + + +void saa716x_ir_exit(struct saa716x_dev *saa716x) +{ + struct infrared *ir = saa716x->ir_priv; + + saa716x->ir_priv = NULL; + tasklet_kill(&ir->tasklet); + del_timer_sync(&ir->keyup_timer); + input_unregister_device(ir->input_dev); + kfree(ir); +} diff --git a/drivers/media/common/saa716x/saa716x_ff_main.c b/drivers/media/common/saa716x/saa716x_ff_main.c new file mode 100644 index 0000000..34093c2 --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_ff_main.c @@ -0,0 +1,1535 @@ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#include "saa716x_mod.h" + +#include "saa716x_dma_reg.h" +#include "saa716x_fgpi_reg.h" +#include "saa716x_greg_reg.h" +#include "saa716x_phi_reg.h" +#include "saa716x_spi_reg.h" +#include "saa716x_msi_reg.h" + +#include "saa716x_vip.h" +#include "saa716x_aip.h" +#include "saa716x_msi.h" +#include "saa716x_adap.h" +#include "saa716x_gpio.h" +#include "saa716x_phi.h" +#include "saa716x_rom.h" +#include "saa716x_spi.h" +#include "saa716x_priv.h" + +#include "saa716x_ff.h" +#include "saa716x_ff_cmd.h" + +#include "stv6110x.h" +#include "stv090x.h" +#include "isl6423.h" + +unsigned int verbose; +module_param(verbose, int, 0644); +MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)"); + +unsigned int int_type; +module_param(int_type, int, 0644); +MODULE_PARM_DESC(int_type, "force Interrupt Handler type: 0=INT-A, 1=MSI, 2=MSI-X. default INT-A mode"); + +unsigned int int_count_enable; +module_param(int_count_enable, int, 0644); +MODULE_PARM_DESC(int_count_enable, "enable counting of interrupts"); + +#define DRIVER_NAME "SAA716x FF" + +static int saa716x_ff_fpga_init(struct saa716x_dev *saa716x) +{ + struct sti7109_dev *sti7109 = saa716x->priv; + int fpgaInit; + int fpgaDone; + int rounds; + int ret; + const struct firmware *fw; + + /* request the FPGA firmware, this will block until someone uploads it */ + ret = request_firmware(&fw, "dvb-ttpremium-fpga-01.fw", &saa716x->pdev->dev); + if (ret) { + if (ret == -ENOENT) { + printk(KERN_ERR "dvb-ttpremium: could not load FPGA firmware," + " file not found: dvb-ttpremium-fpga-01.fw\n"); + printk(KERN_ERR "dvb-ttpremium: usually this should be in " + "/usr/lib/hotplug/firmware or /lib/firmware\n"); + } else + printk(KERN_ERR "dvb-ttpremium: cannot request firmware" + " (error %i)\n", ret); + return -EINVAL; + } + + /* set FPGA PROGRAMN high */ + saa716x_gpio_write(saa716x, TT_PREMIUM_GPIO_FPGA_PROGRAMN, 1); + msleep(10); + + /* set FPGA PROGRAMN low to set it into configuration mode */ + saa716x_gpio_write(saa716x, TT_PREMIUM_GPIO_FPGA_PROGRAMN, 0); + msleep(10); + + /* set FPGA PROGRAMN high to start configuration process */ + saa716x_gpio_write(saa716x, TT_PREMIUM_GPIO_FPGA_PROGRAMN, 1); + + rounds = 0; + fpgaInit = saa716x_gpio_read(saa716x, TT_PREMIUM_GPIO_FPGA_INITN); + while (fpgaInit == 0 && rounds < 5000) { + //msleep(1); + fpgaInit = saa716x_gpio_read(saa716x, TT_PREMIUM_GPIO_FPGA_INITN); + rounds++; + } + dprintk(SAA716x_INFO, 1, "SAA716x FF FPGA INITN=%d, rounds=%d", + fpgaInit, rounds); + + SAA716x_EPWR(SPI, SPI_CLOCK_COUNTER, 0x08); + SAA716x_EPWR(SPI, SPI_CONTROL_REG, SPI_MODE_SELECT); + + msleep(10); + + fpgaDone = saa716x_gpio_read(saa716x, TT_PREMIUM_GPIO_FPGA_DONE); + dprintk(SAA716x_INFO, 1, "SAA716x FF FPGA DONE=%d", fpgaDone); + dprintk(SAA716x_INFO, 1, "SAA716x FF FPGA write bitstream"); + saa716x_spi_write(saa716x, fw->data, fw->size); + dprintk(SAA716x_INFO, 1, "SAA716x FF FPGA write bitstream done"); + fpgaDone = saa716x_gpio_read(saa716x, TT_PREMIUM_GPIO_FPGA_DONE); + dprintk(SAA716x_INFO, 1, "SAA716x FF FPGA DONE=%d", fpgaDone); + + msleep(10); + + release_firmware(fw); + + if (!fpgaDone) { + printk(KERN_ERR "SAA716x FF FPGA is not responding, did you " + "connect the power supply?\n"); + return -EINVAL; + } + + sti7109->fpga_version = SAA716x_EPRD(PHI_1, FPGA_ADDR_VERSION); + printk(KERN_INFO "SAA716x FF FPGA version %X.%02X\n", + sti7109->fpga_version >> 8, sti7109->fpga_version & 0xFF); + + return 0; +} + +static int saa716x_ff_st7109_init(struct saa716x_dev *saa716x) +{ + int i; + int length; + u32 requestedBlock; + u32 writtenBlock; + u32 numBlocks; + u32 blockSize; + u32 lastBlockSize; + u64 startTime; + u64 currentTime; + u64 waitTime; + int ret; + const struct firmware *fw; + u32 loaderVersion; + + /* request the st7109 loader, this will block until someone uploads it */ + ret = request_firmware(&fw, "dvb-ttpremium-loader-01.fw", &saa716x->pdev->dev); + if (ret) { + if (ret == -ENOENT) { + printk(KERN_ERR "dvb-ttpremium: could not load ST7109 loader," + " file not found: dvb-ttpremium-loader-01.fw\n"); + printk(KERN_ERR "dvb-ttpremium: usually this should be in " + "/usr/lib/hotplug/firmware or /lib/firmware\n"); + } else + printk(KERN_ERR "dvb-ttpremium: cannot request firmware" + " (error %i)\n", ret); + return -EINVAL; + } + loaderVersion = (fw->data[0x1385] << 8) | fw->data[0x1384]; + printk(KERN_INFO "SAA716x FF loader version %X.%02X\n", + loaderVersion >> 8, loaderVersion & 0xFF); + + saa716x_phi_write(saa716x, 0, fw->data, fw->size); + msleep(10); + + release_firmware(fw); + + /* take ST out of reset */ + saa716x_gpio_write(saa716x, TT_PREMIUM_GPIO_RESET_BACKEND, 1); + + startTime = jiffies; + waitTime = 0; + do { + requestedBlock = SAA716x_EPRD(PHI_1, 0x3ffc); + if (requestedBlock == 1) + break; + + currentTime = jiffies; + waitTime = currentTime - startTime; + } while (waitTime < (1 * HZ)); + + if (waitTime >= 1 * HZ) { + dprintk(SAA716x_ERROR, 1, "STi7109 seems to be DEAD!"); + return -1; + } + dprintk(SAA716x_INFO, 1, "STi7109 ready after %llu ticks", waitTime); + + /* request the st7109 firmware, this will block until someone uploads it */ + ret = request_firmware(&fw, "dvb-ttpremium-st7109-01.fw", &saa716x->pdev->dev); + if (ret) { + if (ret == -ENOENT) { + printk(KERN_ERR "dvb-ttpremium: could not load ST7109 firmware," + " file not found: dvb-ttpremium-st7109-01.fw\n"); + printk(KERN_ERR "dvb-ttpremium: usually this should be in " + "/usr/lib/hotplug/firmware or /lib/firmware\n"); + } else + printk(KERN_ERR "dvb-ttpremium: cannot request firmware" + " (error %i)\n", ret); + return -EINVAL; + } + + dprintk(SAA716x_INFO, 1, "SAA716x FF download ST7109 firmware"); + writtenBlock = 0; + blockSize = 0x3c00; + length = fw->size; + numBlocks = length / blockSize; + lastBlockSize = length % blockSize; + for (i = 0; i < length; i += blockSize) { + writtenBlock++; + /* write one block (last may differ from blockSize) */ + if (lastBlockSize && writtenBlock == (numBlocks + 1)) + saa716x_phi_write(saa716x, 0, &fw->data[i], lastBlockSize); + else + saa716x_phi_write(saa716x, 0, &fw->data[i], blockSize); + + SAA716x_EPWR(PHI_1, 0x3ff8, writtenBlock); + startTime = jiffies; + waitTime = 0; + do { + requestedBlock = SAA716x_EPRD(PHI_1, 0x3ffc); + if (requestedBlock == (writtenBlock + 1)) + break; + + currentTime = jiffies; + waitTime = currentTime - startTime; + } while (waitTime < (1 * HZ)); + + if (waitTime >= 1 * HZ) { + dprintk(SAA716x_ERROR, 1, "STi7109 seems to be DEAD!"); + release_firmware(fw); + return -1; + } + } + + /* disable frontend support through ST firmware */ + SAA716x_EPWR(PHI_1, 0x3ff4, 1); + + /* indicate end of transfer */ + writtenBlock++; + writtenBlock |= 0x80000000; + SAA716x_EPWR(PHI_1, 0x3ff8, writtenBlock); + + dprintk(SAA716x_INFO, 1, "SAA716x FF download ST7109 firmware done"); + + release_firmware(fw); + + return 0; +} + +static int saa716x_usercopy(struct dvb_device *dvbdev, + unsigned int cmd, unsigned long arg, + int (*func)(struct dvb_device *dvbdev, + unsigned int cmd, void *arg)) +{ + char sbuf[128]; + void *mbuf = NULL; + void *parg = NULL; + int err = -EINVAL; + + /* Copy arguments into temp kernel buffer */ + switch (_IOC_DIR(cmd)) { + case _IOC_NONE: + /* + * For this command, the pointer is actually an integer + * argument. + */ + parg = (void *) arg; + break; + case _IOC_READ: /* some v4l ioctls are marked wrong ... */ + case _IOC_WRITE: + case (_IOC_WRITE | _IOC_READ): + if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { + parg = sbuf; + } else { + /* too big to allocate from stack */ + mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL); + if (NULL == mbuf) + return -ENOMEM; + parg = mbuf; + } + + err = -EFAULT; + if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd))) + goto out; + break; + } + + /* call driver */ + if ((err = func(dvbdev, cmd, parg)) == -ENOIOCTLCMD) + err = -EINVAL; + + if (err < 0) + goto out; + + /* Copy results into user buffer */ + switch (_IOC_DIR(cmd)) + { + case _IOC_READ: + case (_IOC_WRITE | _IOC_READ): + if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd))) + err = -EFAULT; + break; + } + +out: + kfree(mbuf); + return err; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) && !defined(EXPERIMENTAL_TREE) +static int dvb_osd_ioctl(struct inode *inode, struct file *file, +#else +static long dvb_osd_ioctl(struct file *file, +#endif + unsigned int cmd, unsigned long arg) +{ + struct dvb_device *dvbdev = file->private_data; + struct sti7109_dev *sti7109 = dvbdev->priv; + int err = -EINVAL; + + if (!dvbdev) + return -ENODEV; + + if (cmd == OSD_RAW_CMD) { + osd_raw_cmd_t raw_cmd; + u8 hdr[4]; + + err = -EFAULT; + if (copy_from_user(&raw_cmd, (void __user *)arg, + _IOC_SIZE(cmd))) + goto out; + + if (copy_from_user(hdr, (void __user *)raw_cmd.cmd_data, 4)) + goto out; + + if (hdr[3] == 4) + err = sti7109_raw_osd_cmd(sti7109, &raw_cmd); + else + err = sti7109_raw_cmd(sti7109, &raw_cmd); + + if (err) + goto out; + + if (copy_to_user((void __user *)arg, &raw_cmd, _IOC_SIZE(cmd))) + err = -EFAULT; + } + else if (cmd == OSD_RAW_DATA) { + osd_raw_data_t raw_data; + + err = -EFAULT; + if (copy_from_user(&raw_data, (void __user *)arg, + _IOC_SIZE(cmd))) + goto out; + + err = sti7109_raw_data(sti7109, &raw_data); + if (err) + goto out; + + if (copy_to_user((void __user *)arg, &raw_data, _IOC_SIZE(cmd))) + err = -EFAULT; + } + +out: + return err; +} + +static struct file_operations dvb_osd_fops = { + .owner = THIS_MODULE, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) && !defined(EXPERIMENTAL_TREE) + .ioctl = dvb_osd_ioctl, +#else + .unlocked_ioctl = dvb_osd_ioctl, +#endif + .open = dvb_generic_open, + .release = dvb_generic_release, +}; + +static struct dvb_device dvbdev_osd = { + .priv = NULL, + .users = 2, + .writers = 2, + .fops = &dvb_osd_fops, + .kernel_ioctl = NULL, +}; + +static int saa716x_ff_osd_exit(struct saa716x_dev *saa716x) +{ + struct sti7109_dev *sti7109 = saa716x->priv; + + dvb_unregister_device(sti7109->osd_dev); + return 0; +} + +static int saa716x_ff_osd_init(struct saa716x_dev *saa716x) +{ + struct saa716x_adapter *saa716x_adap = saa716x->saa716x_adap; + struct sti7109_dev *sti7109 = saa716x->priv; + + dvb_register_device(&saa716x_adap->dvb_adapter, + &sti7109->osd_dev, + &dvbdev_osd, + sti7109, + DVB_DEVICE_OSD); + + return 0; +} + +static int do_dvb_audio_ioctl(struct dvb_device *dvbdev, + unsigned int cmd, void *parg) +{ + struct sti7109_dev *sti7109 = dvbdev->priv; + //struct saa716x_dev *saa716x = sti7109->dev; + int ret = 0; + + switch (cmd) { + case AUDIO_GET_PTS: + { + *(u64 *)parg = sti7109->audio_pts; + break; + } + default: + ret = -ENOIOCTLCMD; + break; + } + return ret; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) && !defined(EXPERIMENTAL_TREE) +static int dvb_audio_ioctl(struct inode *inode, struct file *file, +#else +static long dvb_audio_ioctl(struct file *file, +#endif + unsigned int cmd, unsigned long arg) +{ + struct dvb_device *dvbdev = file->private_data; + + if (!dvbdev) + return -ENODEV; + + return saa716x_usercopy (dvbdev, cmd, arg, do_dvb_audio_ioctl); +} + +static struct file_operations dvb_audio_fops = { + .owner = THIS_MODULE, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) && !defined(EXPERIMENTAL_TREE) + .ioctl = dvb_audio_ioctl, +#else + .unlocked_ioctl = dvb_audio_ioctl, +#endif + .open = dvb_generic_open, + .release = dvb_generic_release, +}; + +static struct dvb_device dvbdev_audio = { + .priv = NULL, + .users = 1, + .writers = 1, + .fops = &dvb_audio_fops, + .kernel_ioctl = NULL, +}; + +static int saa716x_ff_audio_exit(struct saa716x_dev *saa716x) +{ + struct sti7109_dev *sti7109 = saa716x->priv; + + dvb_unregister_device(sti7109->audio_dev); + return 0; +} + +static int saa716x_ff_audio_init(struct saa716x_dev *saa716x) +{ + struct saa716x_adapter *saa716x_adap = saa716x->saa716x_adap; + struct sti7109_dev *sti7109 = saa716x->priv; + + dvb_register_device(&saa716x_adap->dvb_adapter, + &sti7109->audio_dev, + &dvbdev_audio, + sti7109, + DVB_DEVICE_AUDIO); + + return 0; +} + +static void fifo_worker(unsigned long data) +{ + struct saa716x_dev *saa716x = (struct saa716x_dev *) data; + struct sti7109_dev *sti7109 = saa716x->priv; + u32 fifoCtrl; + u32 fifoStat; + u16 fifoSize; + u16 fifoUsage; + u16 fifoFree; + int len; + + fifoCtrl = SAA716x_EPRD(PHI_1, FPGA_ADDR_FIFO_CTRL); + fifoStat = SAA716x_EPRD(PHI_1, FPGA_ADDR_FIFO_STAT); + fifoSize = (u16) (fifoStat >> 16); + fifoUsage = (u16) fifoStat; + fifoFree = fifoSize - fifoUsage; + spin_lock(&sti7109->tsout.lock); + len = dvb_ringbuffer_avail(&sti7109->tsout); + if (len > fifoFree) + len = fifoFree; + if (len >= TS_SIZE) + { + while (len >= TS_SIZE) + { + dvb_ringbuffer_read(&sti7109->tsout, sti7109->tsbuf, (size_t) TS_SIZE); + saa716x_phi_write_fifo(saa716x, sti7109->tsbuf, TS_SIZE); + len -= TS_SIZE; + } + wake_up(&sti7109->tsout.queue); + fifoCtrl |= 0x4; + SAA716x_EPWR(PHI_1, FPGA_ADDR_FIFO_CTRL, fifoCtrl); + } + spin_unlock(&sti7109->tsout.lock); +} + +#define FREE_COND_TS (dvb_ringbuffer_free(&sti7109->tsout) >= TS_SIZE) + +static ssize_t dvb_video_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct dvb_device *dvbdev = file->private_data; + struct sti7109_dev *sti7109 = dvbdev->priv; + struct saa716x_dev *saa716x = sti7109->dev; + unsigned long todo = count; + + if ((file->f_flags & O_ACCMODE) == O_RDONLY) + return -EPERM; +/* + if (av7110->videostate.stream_source != VIDEO_SOURCE_MEMORY) + return -EPERM; +*/ + if ((file->f_flags & O_NONBLOCK) && !FREE_COND_TS) + return -EWOULDBLOCK; + + while (todo >= TS_SIZE) { + if (!FREE_COND_TS) { + if (file->f_flags & O_NONBLOCK) + break; + if (wait_event_interruptible(sti7109->tsout.queue, FREE_COND_TS)) + break; + } + dvb_ringbuffer_write(&sti7109->tsout, buf, TS_SIZE); + todo -= TS_SIZE; + buf += TS_SIZE; + } + + if (count > todo) { + u32 fifoCtrl; + + fifoCtrl = SAA716x_EPRD(PHI_1, FPGA_ADDR_FIFO_CTRL); + fifoCtrl |= 0x4; + SAA716x_EPWR(PHI_1, FPGA_ADDR_FIFO_CTRL, fifoCtrl); + } + + return count - todo; +} + +static unsigned int dvb_video_poll(struct file *file, poll_table *wait) +{ + struct dvb_device *dvbdev = file->private_data; + struct sti7109_dev *sti7109 = dvbdev->priv; + unsigned int mask = 0; + + if ((file->f_flags & O_ACCMODE) != O_RDONLY) + poll_wait(file, &sti7109->tsout.queue, wait); + + if ((file->f_flags & O_ACCMODE) != O_RDONLY) { + if (1/*sti7109->playing*/) { + if (FREE_COND_TS) + mask |= (POLLOUT | POLLWRNORM); + } else /* if not playing: may play if asked for */ + mask |= (POLLOUT | POLLWRNORM); + } + + return mask; +} + +static int do_dvb_video_ioctl(struct dvb_device *dvbdev, + unsigned int cmd, void *parg) +{ + struct sti7109_dev *sti7109 = dvbdev->priv; + struct saa716x_dev *saa716x = sti7109->dev; + int ret = 0; + + switch (cmd) { + case VIDEO_SELECT_SOURCE: + { + video_stream_source_t stream_source; + + stream_source = (video_stream_source_t) parg; + if (stream_source == VIDEO_SOURCE_DEMUX) { + /* stop and reset FIFO 1 */ + SAA716x_EPWR(PHI_1, FPGA_ADDR_FIFO_CTRL, 1); + } + else { + dvb_ringbuffer_flush_spinlock_wakeup(&sti7109->tsout); + /* reset FIFO 1 */ + SAA716x_EPWR(PHI_1, FPGA_ADDR_FIFO_CTRL, 1); + /* start FIFO 1 */ + SAA716x_EPWR(PHI_1, FPGA_ADDR_FIFO_CTRL, 2); + } + break; + } + case VIDEO_CLEAR_BUFFER: + { + dvb_ringbuffer_flush_spinlock_wakeup(&sti7109->tsout); + break; + } + case VIDEO_GET_PTS: + { + *(u64 *)parg = sti7109->video_pts; + break; + } + case VIDEO_GET_SIZE: + { + ret = sti7109_cmd_get_video_format(sti7109, (video_size_t *) parg); + break; + } + default: + ret = -ENOIOCTLCMD; + break; + } + return ret; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) && !defined(EXPERIMENTAL_TREE) +static int dvb_video_ioctl(struct inode *inode, struct file *file, +#else +static long dvb_video_ioctl(struct file *file, +#endif + unsigned int cmd, unsigned long arg) +{ + struct dvb_device *dvbdev = file->private_data; + + if (!dvbdev) + return -ENODEV; + + return saa716x_usercopy (dvbdev, cmd, arg, do_dvb_video_ioctl); +} + +static struct file_operations dvb_video_fops = { + .owner = THIS_MODULE, + .write = dvb_video_write, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36) && !defined(EXPERIMENTAL_TREE) + .ioctl = dvb_video_ioctl, +#else + .unlocked_ioctl = dvb_video_ioctl, +#endif + .open = dvb_generic_open, + .release = dvb_generic_release, + .poll = dvb_video_poll, +}; + +static struct dvb_device dvbdev_video = { + .priv = NULL, + .users = 1, + .writers = 1, + .fops = &dvb_video_fops, + .kernel_ioctl = NULL, +}; + +static int saa716x_ff_video_exit(struct saa716x_dev *saa716x) +{ + struct sti7109_dev *sti7109 = saa716x->priv; + + tasklet_kill(&sti7109->fifo_tasklet); + dvb_unregister_device(sti7109->video_dev); + return 0; +} + +static int saa716x_ff_video_init(struct saa716x_dev *saa716x) +{ + struct saa716x_adapter *saa716x_adap = saa716x->saa716x_adap; + struct sti7109_dev *sti7109 = saa716x->priv; + + dvb_ringbuffer_init(&sti7109->tsout, sti7109->iobuf, TSOUT_LEN); + sti7109->tsbuf = (u8 *) (sti7109->iobuf + TSOUT_LEN); + + dvb_register_device(&saa716x_adap->dvb_adapter, + &sti7109->video_dev, + &dvbdev_video, + sti7109, + DVB_DEVICE_VIDEO); + + tasklet_init(&sti7109->fifo_tasklet, fifo_worker, + (unsigned long)saa716x); + + return 0; +} + +static int saa716x_ff_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) +{ + struct saa716x_dev *saa716x; + struct sti7109_dev *sti7109; + int err = 0; + u32 value; + unsigned long timeout; + u32 fw_version; + + saa716x = kzalloc(sizeof (struct saa716x_dev), GFP_KERNEL); + if (saa716x == NULL) { + printk(KERN_ERR "saa716x_budget_pci_probe ERROR: out of memory\n"); + err = -ENOMEM; + goto fail0; + } + + saa716x->verbose = verbose; + saa716x->int_type = int_type; + saa716x->pdev = pdev; + saa716x->config = (struct saa716x_config *) pci_id->driver_data; + + err = saa716x_pci_init(saa716x); + if (err) { + dprintk(SAA716x_ERROR, 1, "SAA716x PCI Initialization failed"); + goto fail1; + } + + err = saa716x_cgu_init(saa716x); + if (err) { + dprintk(SAA716x_ERROR, 1, "SAA716x CGU Init failed"); + goto fail1; + } + + err = saa716x_core_boot(saa716x); + if (err) { + dprintk(SAA716x_ERROR, 1, "SAA716x Core Boot failed"); + goto fail2; + } + dprintk(SAA716x_DEBUG, 1, "SAA716x Core Boot Success"); + + err = saa716x_msi_init(saa716x); + if (err) { + dprintk(SAA716x_ERROR, 1, "SAA716x MSI Init failed"); + goto fail2; + } + + err = saa716x_jetpack_init(saa716x); + if (err) { + dprintk(SAA716x_ERROR, 1, "SAA716x Jetpack core initialization failed"); + goto fail1; + } + + err = saa716x_i2c_init(saa716x); + if (err) { + dprintk(SAA716x_ERROR, 1, "SAA716x I2C Initialization failed"); + goto fail3; + } + + err = saa716x_phi_init(saa716x); + if (err) { + dprintk(SAA716x_ERROR, 1, "SAA716x PHI Initialization failed"); + goto fail3; + } + + saa716x_gpio_init(saa716x); + + /* prepare the sti7109 device struct */ + sti7109 = kzalloc(sizeof(struct sti7109_dev), GFP_KERNEL); + if (!sti7109) { + dprintk(SAA716x_ERROR, 1, "SAA716x: out of memory"); + goto fail3; + } + + sti7109->dev = saa716x; + + sti7109->iobuf = vmalloc(TSOUT_LEN + TSBUF_LEN + MAX_DATA_LEN); + if (!sti7109->iobuf) + goto fail4; + + sti7109_cmd_init(sti7109); + + sti7109->int_count_enable = int_count_enable; + sti7109->total_int_count = 0; + memset(sti7109->fgpi_int_count, 0, sizeof(sti7109->fgpi_int_count)); + memset(sti7109->i2c_int_count, 0, sizeof(sti7109->i2c_int_count)); + sti7109->ext_int_total_count = 0; + memset(sti7109->ext_int_source_count, 0, sizeof(sti7109->ext_int_source_count)); + sti7109->last_int_ticks = jiffies; + + saa716x->priv = sti7109; + + saa716x_gpio_set_output(saa716x, TT_PREMIUM_GPIO_POWER_ENABLE); + saa716x_gpio_set_output(saa716x, TT_PREMIUM_GPIO_RESET_BACKEND); + saa716x_gpio_set_output(saa716x, TT_PREMIUM_GPIO_FPGA_CS0); + saa716x_gpio_set_mode(saa716x, TT_PREMIUM_GPIO_FPGA_CS0, 1); + saa716x_gpio_set_output(saa716x, TT_PREMIUM_GPIO_FPGA_CS1); + saa716x_gpio_set_mode(saa716x, TT_PREMIUM_GPIO_FPGA_CS1, 1); + saa716x_gpio_set_output(saa716x, TT_PREMIUM_GPIO_FPGA_PROGRAMN); + saa716x_gpio_set_input(saa716x, TT_PREMIUM_GPIO_FPGA_DONE); + saa716x_gpio_set_input(saa716x, TT_PREMIUM_GPIO_FPGA_INITN); + + /* hold ST in reset */ + saa716x_gpio_write(saa716x, TT_PREMIUM_GPIO_RESET_BACKEND, 0); + + /* enable board power */ + saa716x_gpio_write(saa716x, TT_PREMIUM_GPIO_POWER_ENABLE, 1); + msleep(100); + + err = saa716x_ff_fpga_init(saa716x); + if (err) { + dprintk(SAA716x_ERROR, 1, "SAA716x FF FPGA Initialization failed"); + goto fail5; + } + + /* configure TS muxer */ + if (sti7109->fpga_version < 0x110) { + /* select FIFO 1 for TS mux 3 */ + SAA716x_EPWR(PHI_1, FPGA_ADDR_TSR_MUX3, 4); + } else { + /* select FIFO 1 for TS mux 3 */ + SAA716x_EPWR(PHI_1, FPGA_ADDR_TSR_MUX3, 1); + } + + /* enable interrupts from ST7109 -> PC */ + SAA716x_EPWR(PHI_1, FPGA_ADDR_EMI_ICTRL, 0x3); + + value = SAA716x_EPRD(MSI, MSI_CONFIG33); + value &= 0xFCFFFFFF; + value |= MSI_INT_POL_EDGE_FALL; + SAA716x_EPWR(MSI, MSI_CONFIG33, value); + SAA716x_EPWR(MSI, MSI_INT_ENA_SET_H, MSI_INT_EXTINT_0); + + /* enable tuner reset */ + SAA716x_EPWR(PHI_1, FPGA_ADDR_PIO_CTRL, 0); + msleep(50); + /* disable tuner reset */ + SAA716x_EPWR(PHI_1, FPGA_ADDR_PIO_CTRL, 1); + + err = saa716x_ff_st7109_init(saa716x); + if (err) { + dprintk(SAA716x_ERROR, 1, "SAA716x FF STi7109 initialization failed"); + goto fail5; + } + + err = saa716x_dump_eeprom(saa716x); + if (err) { + dprintk(SAA716x_ERROR, 1, "SAA716x EEPROM dump failed"); + } + + err = saa716x_eeprom_data(saa716x); + if (err) { + dprintk(SAA716x_ERROR, 1, "SAA716x EEPROM dump failed"); + } + + /* enable FGPI2 and FGPI3 for TS inputs */ + SAA716x_EPWR(GREG, GREG_VI_CTRL, 0x0689F04); + SAA716x_EPWR(GREG, GREG_FGPI_CTRL, 0x280); + + err = saa716x_dvb_init(saa716x); + if (err) { + dprintk(SAA716x_ERROR, 1, "SAA716x DVB initialization failed"); + goto fail6; + } + + /* wait a maximum of 10 seconds for the STi7109 to boot */ + timeout = 10 * HZ; + timeout = wait_event_interruptible_timeout(sti7109->boot_finish_wq, + sti7109->boot_finished == 1, + timeout); + + if (timeout == -ERESTARTSYS || sti7109->boot_finished == 0) { + if (timeout == -ERESTARTSYS) { + /* a signal arrived */ + goto fail6; + } + dprintk(SAA716x_ERROR, 1, "timed out waiting for boot finish"); + err = -1; + goto fail6; + } + dprintk(SAA716x_INFO, 1, "STi7109 finished booting"); + + err = saa716x_ff_video_init(saa716x); + if (err) { + dprintk(SAA716x_ERROR, 1, "SAA716x FF VIDEO initialization failed"); + goto fail7; + } + + err = saa716x_ff_audio_init(saa716x); + if (err) { + dprintk(SAA716x_ERROR, 1, "SAA716x FF AUDIO initialization failed"); + goto fail8; + } + + err = saa716x_ff_osd_init(saa716x); + if (err) { + dprintk(SAA716x_ERROR, 1, "SAA716x FF OSD initialization failed"); + goto fail9; + } + + err = sti7109_cmd_get_fw_version(sti7109, &fw_version); + if (!err) { + printk(KERN_INFO "SAA716x FF firmware version %X.%X.%X\n", + (fw_version >> 16) & 0xFF, (fw_version >> 8) & 0xFF, + fw_version & 0xFF); + } + + err = saa716x_ir_init(saa716x); + if (err) + goto fail9; + + return 0; + +fail9: + saa716x_ff_osd_exit(saa716x); +fail8: + saa716x_ff_audio_exit(saa716x); +fail7: + saa716x_ff_video_exit(saa716x); +fail6: + saa716x_dvb_exit(saa716x); +fail5: + SAA716x_EPWR(MSI, MSI_INT_ENA_CLR_H, MSI_INT_EXTINT_0); + + /* disable board power */ + saa716x_gpio_write(saa716x, TT_PREMIUM_GPIO_POWER_ENABLE, 0); + + vfree(sti7109->iobuf); +fail4: + kfree(sti7109); +fail3: + saa716x_i2c_exit(saa716x); +fail2: + saa716x_pci_exit(saa716x); +fail1: + kfree(saa716x); +fail0: + return err; +} + +static void saa716x_ff_pci_remove(struct pci_dev *pdev) +{ + struct saa716x_dev *saa716x = pci_get_drvdata(pdev); + struct sti7109_dev *sti7109 = saa716x->priv; + + saa716x_ir_exit(saa716x); + + saa716x_ff_osd_exit(saa716x); + + saa716x_ff_audio_exit(saa716x); + + saa716x_ff_video_exit(saa716x); + + saa716x_dvb_exit(saa716x); + + SAA716x_EPWR(MSI, MSI_INT_ENA_CLR_H, MSI_INT_EXTINT_0); + + /* disable board power */ + saa716x_gpio_write(saa716x, TT_PREMIUM_GPIO_POWER_ENABLE, 0); + + vfree(sti7109->iobuf); + + saa716x->priv = NULL; + kfree(sti7109); + + saa716x_i2c_exit(saa716x); + saa716x_pci_exit(saa716x); + kfree(saa716x); +} + +static void demux_worker(unsigned long data) +{ + struct saa716x_fgpi_stream_port *fgpi_entry = (struct saa716x_fgpi_stream_port *)data; + struct saa716x_dev *saa716x = fgpi_entry->saa716x; + struct dvb_demux *demux; + u32 fgpi_index; + u32 i; + u32 write_index; + + fgpi_index = fgpi_entry->dma_channel - 6; + demux = NULL; + for (i = 0; i < saa716x->config->adapters; i++) { + if (saa716x->config->adap_config[i].ts_port == fgpi_index) { + demux = &saa716x->saa716x_adap[i].demux; + break; + } + } + if (demux == NULL) { + printk(KERN_ERR "%s: unexpected channel %u\n", + __func__, fgpi_entry->dma_channel); + return; + } + + write_index = saa716x_fgpi_get_write_index(saa716x, fgpi_index); + if (write_index < 0) + return; + + dprintk(SAA716x_DEBUG, 1, "dma buffer = %d", write_index); + + if (write_index == fgpi_entry->read_index) { + printk(KERN_DEBUG "%s: called but nothing to do\n", __func__); + return; + } + + do { + u8 *data = (u8 *)fgpi_entry->dma_buf[fgpi_entry->read_index].mem_virt; + + pci_dma_sync_sg_for_cpu(saa716x->pdev, + fgpi_entry->dma_buf[fgpi_entry->read_index].sg_list, + fgpi_entry->dma_buf[fgpi_entry->read_index].list_len, + PCI_DMA_FROMDEVICE); + + dvb_dmx_swfilter(demux, data, 348 * 188); + + fgpi_entry->read_index = (fgpi_entry->read_index + 1) & 7; + } while (write_index != fgpi_entry->read_index); +} + +static irqreturn_t saa716x_ff_pci_irq(int irq, void *dev_id) +{ + struct saa716x_dev *saa716x = (struct saa716x_dev *) dev_id; + struct sti7109_dev *sti7109; + u32 msiStatusL; + u32 msiStatusH; + u32 phiISR; + + if (unlikely(saa716x == NULL)) { + printk("%s: saa716x=NULL", __func__); + return IRQ_NONE; + } + sti7109 = saa716x->priv; + if (unlikely(sti7109 == NULL)) { + printk("%s: sti7109=NULL", __func__); + return IRQ_NONE; + } + if (sti7109->int_count_enable) + sti7109->total_int_count++; +#if 0 + dprintk(SAA716x_DEBUG, 1, "VI STAT 0=<%02x> 1=<%02x>, CTL 1=<%02x> 2=<%02x>", + SAA716x_EPRD(VI0, INT_STATUS), + SAA716x_EPRD(VI1, INT_STATUS), + SAA716x_EPRD(VI0, INT_ENABLE), + SAA716x_EPRD(VI1, INT_ENABLE)); + + dprintk(SAA716x_DEBUG, 1, "FGPI STAT 0=<%02x> 1=<%02x>, CTL 1=<%02x> 2=<%02x>", + SAA716x_EPRD(FGPI0, INT_STATUS), + SAA716x_EPRD(FGPI1, INT_STATUS), + SAA716x_EPRD(FGPI0, INT_ENABLE), + SAA716x_EPRD(FGPI0, INT_ENABLE)); + + dprintk(SAA716x_DEBUG, 1, "FGPI STAT 2=<%02x> 3=<%02x>, CTL 2=<%02x> 3=<%02x>", + SAA716x_EPRD(FGPI2, INT_STATUS), + SAA716x_EPRD(FGPI3, INT_STATUS), + SAA716x_EPRD(FGPI2, INT_ENABLE), + SAA716x_EPRD(FGPI3, INT_ENABLE)); + + dprintk(SAA716x_DEBUG, 1, "AI STAT 0=<%02x> 1=<%02x>, CTL 0=<%02x> 1=<%02x>", + SAA716x_EPRD(AI0, AI_STATUS), + SAA716x_EPRD(AI1, AI_STATUS), + SAA716x_EPRD(AI0, AI_CTL), + SAA716x_EPRD(AI1, AI_CTL)); + + dprintk(SAA716x_DEBUG, 1, "MSI STAT L=<%02x> H=<%02x>, CTL L=<%02x> H=<%02x>", + SAA716x_EPRD(MSI, MSI_INT_STATUS_L), + SAA716x_EPRD(MSI, MSI_INT_STATUS_H), + SAA716x_EPRD(MSI, MSI_INT_ENA_L), + SAA716x_EPRD(MSI, MSI_INT_ENA_H)); + + dprintk(SAA716x_DEBUG, 1, "I2C STAT 0=<%02x> 1=<%02x>, CTL 0=<%02x> 1=<%02x>", + SAA716x_EPRD(I2C_A, INT_STATUS), + SAA716x_EPRD(I2C_B, INT_STATUS), + SAA716x_EPRD(I2C_A, INT_ENABLE), + SAA716x_EPRD(I2C_B, INT_ENABLE)); + + dprintk(SAA716x_DEBUG, 1, "DCS STAT=<%02x>, CTL=<%02x>", + SAA716x_EPRD(DCS, DCSC_INT_STATUS), + SAA716x_EPRD(DCS, DCSC_INT_ENABLE)); +#endif + msiStatusL = SAA716x_EPRD(MSI, MSI_INT_STATUS_L); + SAA716x_EPWR(MSI, MSI_INT_STATUS_CLR_L, msiStatusL); + msiStatusH = SAA716x_EPRD(MSI, MSI_INT_STATUS_H); + SAA716x_EPWR(MSI, MSI_INT_STATUS_CLR_H, msiStatusH); + + if (msiStatusL) { + if (msiStatusL & MSI_INT_TAGACK_FGPI_2) { + if (sti7109->int_count_enable) + sti7109->fgpi_int_count[0]++; + tasklet_schedule(&saa716x->fgpi[2].tasklet); + } + if (msiStatusL & MSI_INT_TAGACK_FGPI_3) { + if (sti7109->int_count_enable) + sti7109->fgpi_int_count[1]++; + tasklet_schedule(&saa716x->fgpi[3].tasklet); + } + } + if (msiStatusH) { + //dprintk(SAA716x_INFO, 1, "msiStatusH: %08X", msiStatusH); + } + + if (msiStatusH & MSI_INT_I2CINT_0) { + if (sti7109->int_count_enable) + sti7109->i2c_int_count[0]++; + saa716x->i2c[0].i2c_op = 0; + wake_up(&saa716x->i2c[0].i2c_wq); + } + if (msiStatusH & MSI_INT_I2CINT_1) { + if (sti7109->int_count_enable) + sti7109->i2c_int_count[1]++; + saa716x->i2c[1].i2c_op = 0; + wake_up(&saa716x->i2c[1].i2c_wq); + } + + if (msiStatusH & MSI_INT_EXTINT_0) { + + phiISR = SAA716x_EPRD(PHI_1, FPGA_ADDR_EMI_ISR); + //dprintk(SAA716x_INFO, 1, "interrupt status register: %08X", phiISR); + + if (sti7109->int_count_enable) { + int i; + sti7109->ext_int_total_count++; + for (i = 0; i < 16; i++) + if (phiISR & (1 << i)) + sti7109->ext_int_source_count[i]++; + } + + if (phiISR & ISR_CMD_MASK) { + + u32 value; + u32 length; + /*dprintk(SAA716x_INFO, 1, "CMD interrupt source");*/ + + value = SAA716x_EPRD(PHI_1, ADDR_CMD_DATA); + value = __cpu_to_be32(value); + length = (value >> 16) + 2; + + /*dprintk(SAA716x_INFO, 1, "CMD length: %d", length);*/ + + if (length > MAX_RESULT_LEN) { + dprintk(SAA716x_ERROR, 1, "CMD length %d > %d", length, MAX_RESULT_LEN); + length = MAX_RESULT_LEN; + } + + saa716x_phi_read(saa716x, ADDR_CMD_DATA, sti7109->result_data, length); + sti7109->result_len = length; + sti7109->result_avail = 1; + wake_up(&sti7109->result_avail_wq); + + phiISR &= ~ISR_CMD_MASK; + SAA716x_EPWR(PHI_1, FPGA_ADDR_EMI_ICLR, ISR_CMD_MASK); + } + + if (phiISR & ISR_READY_MASK) { + /*dprintk(SAA716x_INFO, 1, "READY interrupt source");*/ + sti7109->cmd_ready = 1; + wake_up(&sti7109->cmd_ready_wq); + phiISR &= ~ISR_READY_MASK; + SAA716x_EPWR(PHI_1, FPGA_ADDR_EMI_ICLR, ISR_READY_MASK); + } + + if (phiISR & ISR_OSD_CMD_MASK) { + + u32 value; + u32 length; + /*dprintk(SAA716x_INFO, 1, "OSD CMD interrupt source");*/ + + value = SAA716x_EPRD(PHI_1, ADDR_OSD_CMD_DATA); + value = __cpu_to_be32(value); + length = (value >> 16) + 2; + + /*dprintk(SAA716x_INFO, 1, "OSD CMD length: %d", length);*/ + + if (length > MAX_RESULT_LEN) { + dprintk(SAA716x_ERROR, 1, "OSD CMD length %d > %d", length, MAX_RESULT_LEN); + length = MAX_RESULT_LEN; + } + + saa716x_phi_read(saa716x, ADDR_OSD_CMD_DATA, sti7109->osd_result_data, length); + sti7109->osd_result_len = length; + sti7109->osd_result_avail = 1; + wake_up(&sti7109->osd_result_avail_wq); + + phiISR &= ~ISR_OSD_CMD_MASK; + SAA716x_EPWR(PHI_1, FPGA_ADDR_EMI_ICLR, ISR_OSD_CMD_MASK); + } + + if (phiISR & ISR_OSD_READY_MASK) { + /*dprintk(SAA716x_INFO, 1, "OSD_READY interrupt source");*/ + sti7109->osd_cmd_ready = 1; + wake_up(&sti7109->osd_cmd_ready_wq); + phiISR &= ~ISR_OSD_READY_MASK; + SAA716x_EPWR(PHI_1, FPGA_ADDR_EMI_ICLR, ISR_OSD_READY_MASK); + } + + if (phiISR & ISR_BLOCK_MASK) { + /*dprintk(SAA716x_INFO, 1, "BLOCK interrupt source");*/ + sti7109->block_done = 1; + wake_up(&sti7109->block_done_wq); + phiISR &= ~ISR_BLOCK_MASK; + SAA716x_EPWR(PHI_1, FPGA_ADDR_EMI_ICLR, ISR_BLOCK_MASK); + } + + if (phiISR & ISR_DATA_MASK) { + /*dprintk(SAA716x_INFO, 1, "DATA interrupt source");*/ + sti7109->data_ready = 1; + wake_up(&sti7109->data_ready_wq); + phiISR &= ~ISR_DATA_MASK; + SAA716x_EPWR(PHI_1, FPGA_ADDR_EMI_ICLR, ISR_DATA_MASK); + } + + if (phiISR & ISR_BOOT_FINISH_MASK) { + /*dprintk(SAA716x_INFO, 1, "BOOT FINISH interrupt source");*/ + sti7109->boot_finished = 1; + wake_up(&sti7109->boot_finish_wq); + phiISR &= ~ISR_BOOT_FINISH_MASK; + SAA716x_EPWR(PHI_1, FPGA_ADDR_EMI_ICLR, ISR_BOOT_FINISH_MASK); + } + + if (phiISR & ISR_AUDIO_PTS_MASK) { + u8 data[8]; + + saa716x_phi_read(saa716x, ADDR_AUDIO_PTS, data, 8); + sti7109->audio_pts = (((u64) data[3] & 0x01) << 32) + | ((u64) data[4] << 24) + | ((u64) data[5] << 16) + | ((u64) data[6] << 8) + | ((u64) data[7]); + + phiISR &= ~ISR_AUDIO_PTS_MASK; + SAA716x_EPWR(PHI_1, FPGA_ADDR_EMI_ICLR, ISR_AUDIO_PTS_MASK); + + /*dprintk(SAA716x_INFO, 1, "AUDIO PTS: %llX", sti7109->audio_pts);*/ + } + + if (phiISR & ISR_VIDEO_PTS_MASK) { + u8 data[8]; + + saa716x_phi_read(saa716x, ADDR_VIDEO_PTS, data, 8); + sti7109->video_pts = (((u64) data[3] & 0x01) << 32) + | ((u64) data[4] << 24) + | ((u64) data[5] << 16) + | ((u64) data[6] << 8) + | ((u64) data[7]); + + phiISR &= ~ISR_VIDEO_PTS_MASK; + SAA716x_EPWR(PHI_1, FPGA_ADDR_EMI_ICLR, ISR_VIDEO_PTS_MASK); + + /*dprintk(SAA716x_INFO, 1, "VIDEO PTS: %llX", sti7109->video_pts);*/ + } + + if (phiISR & ISR_CURRENT_STC_MASK) { + u8 data[8]; + + saa716x_phi_read(saa716x, ADDR_CURRENT_STC, data, 8); + sti7109->current_stc = (((u64) data[3] & 0x01) << 32) + | ((u64) data[4] << 24) + | ((u64) data[5] << 16) + | ((u64) data[6] << 8) + | ((u64) data[7]); + + phiISR &= ~ISR_CURRENT_STC_MASK; + SAA716x_EPWR(PHI_1, FPGA_ADDR_EMI_ICLR, ISR_CURRENT_STC_MASK); + + /*dprintk(SAA716x_INFO, 1, "CURRENT STC: %llu", sti7109->current_stc);*/ + } + + if (phiISR & ISR_REMOTE_EVENT_MASK) { + u8 data[4]; + u32 remote_event; + + saa716x_phi_read(saa716x, ADDR_REMOTE_EVENT, data, 4); + remote_event = (data[3] << 24) + | (data[2] << 16) + | (data[1] << 8) + | (data[0]); + memset(data, 0, sizeof(data)); + saa716x_phi_write(saa716x, ADDR_REMOTE_EVENT, data, 4); + + phiISR &= ~ISR_REMOTE_EVENT_MASK; + SAA716x_EPWR(PHI_1, FPGA_ADDR_EMI_ICLR, ISR_REMOTE_EVENT_MASK); + + if (remote_event == 0) { + dprintk(SAA716x_ERROR, 1, "REMOTE EVENT: %X ignored", remote_event); + } else { + dprintk(SAA716x_INFO, 1, "REMOTE EVENT: %X", remote_event); + saa716x_ir_handler(saa716x, remote_event); + } + } + + if (phiISR & ISR_DVO_FORMAT_MASK) { + u8 data[4]; + u32 format; + + saa716x_phi_read(saa716x, ADDR_DVO_FORMAT, data, 4); + format = (data[0] << 24) + | (data[1] << 16) + | (data[2] << 8) + | (data[3]); + + phiISR &= ~ISR_DVO_FORMAT_MASK; + SAA716x_EPWR(PHI_1, FPGA_ADDR_EMI_ICLR, ISR_DVO_FORMAT_MASK); + + dprintk(SAA716x_INFO, 1, "DVO FORMAT CHANGE: %u", format); + } + + if (phiISR & ISR_LOG_MESSAGE_MASK) { + char message[SIZE_LOG_MESSAGE_DATA]; + + saa716x_phi_read(saa716x, ADDR_LOG_MESSAGE, message, + SIZE_LOG_MESSAGE_DATA); + + phiISR &= ~ISR_LOG_MESSAGE_MASK; + SAA716x_EPWR(PHI_1, FPGA_ADDR_EMI_ICLR, ISR_LOG_MESSAGE_MASK); + + dprintk(SAA716x_INFO, 1, "LOG MESSAGE: %.*s", + SIZE_LOG_MESSAGE_DATA, message); + } + + if (phiISR & ISR_FIFO1_EMPTY_MASK) { + u32 fifoCtrl; + + /*dprintk(SAA716x_INFO, 1, "FIFO EMPTY interrupt source");*/ + fifoCtrl = SAA716x_EPRD(PHI_1, FPGA_ADDR_FIFO_CTRL); + fifoCtrl &= ~0x4; + SAA716x_EPWR(PHI_1, FPGA_ADDR_FIFO_CTRL, fifoCtrl); + tasklet_schedule(&sti7109->fifo_tasklet); + phiISR &= ~ISR_FIFO1_EMPTY_MASK; + } + + if (phiISR) { + dprintk(SAA716x_INFO, 1, "unknown interrupt source"); + SAA716x_EPWR(PHI_1, FPGA_ADDR_EMI_ICLR, phiISR); + } + } + + if (sti7109->int_count_enable) { + if (jiffies - sti7109->last_int_ticks >= HZ) { + dprintk(SAA716x_INFO, 1, "int count: t: %d, f:%d %d, i:%d %d," + "e: %d (%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d)", + sti7109->total_int_count, + sti7109->fgpi_int_count[0], + sti7109->fgpi_int_count[1], + sti7109->i2c_int_count[0], + sti7109->i2c_int_count[1], + sti7109->ext_int_total_count, + sti7109->ext_int_source_count[0], + sti7109->ext_int_source_count[1], + sti7109->ext_int_source_count[2], + sti7109->ext_int_source_count[3], + sti7109->ext_int_source_count[4], + sti7109->ext_int_source_count[5], + sti7109->ext_int_source_count[6], + sti7109->ext_int_source_count[7], + sti7109->ext_int_source_count[8], + sti7109->ext_int_source_count[9], + sti7109->ext_int_source_count[10], + sti7109->ext_int_source_count[11], + sti7109->ext_int_source_count[12], + sti7109->ext_int_source_count[13], + sti7109->ext_int_source_count[14], + sti7109->ext_int_source_count[15]); + sti7109->total_int_count = 0; + memset(sti7109->fgpi_int_count, 0, sizeof(sti7109->fgpi_int_count)); + memset(sti7109->i2c_int_count, 0, sizeof(sti7109->i2c_int_count)); + sti7109->ext_int_total_count = 0; + memset(sti7109->ext_int_source_count, 0, sizeof(sti7109->ext_int_source_count)); + sti7109->last_int_ticks = jiffies; + } + } + return IRQ_HANDLED; +} + +#define SAA716x_MODEL_S2_6400_DUAL "Technotrend S2 6400 Dual S2 Premium" +#define SAA716x_DEV_S2_6400_DUAL "2x DVB-S/S2 + Hardware decode" + +static struct stv090x_config tt6400_stv090x_config = { + .device = STV0900, + .demod_mode = STV090x_DUAL, + .clk_mode = STV090x_CLK_EXT, + + .xtal = 13500000, + .address = 0x68, + + .ts1_mode = STV090x_TSMODE_SERIAL_CONTINUOUS, + .ts2_mode = STV090x_TSMODE_SERIAL_CONTINUOUS, + .ts1_clk = 135000000, + .ts2_clk = 135000000, + + .repeater_level = STV090x_RPTLEVEL_16, + + .tuner_init = NULL, + .tuner_set_mode = NULL, + .tuner_set_frequency = NULL, + .tuner_get_frequency = NULL, + .tuner_set_bandwidth = NULL, + .tuner_get_bandwidth = NULL, + .tuner_set_bbgain = NULL, + .tuner_get_bbgain = NULL, + .tuner_set_refclk = NULL, + .tuner_get_status = NULL, +}; + +static struct stv6110x_config tt6400_stv6110x_config = { + .addr = 0x60, + .refclk = 27000000, + .clk_div = 2, +}; + +static struct isl6423_config tt6400_isl6423_config[2] = { + { + .current_max = SEC_CURRENT_515m, + .curlim = SEC_CURRENT_LIM_ON, + .mod_extern = 1, + .addr = 0x09, + }, + { + .current_max = SEC_CURRENT_515m, + .curlim = SEC_CURRENT_LIM_ON, + .mod_extern = 1, + .addr = 0x08, + } +}; + + +static int saa716x_s26400_frontend_attach(struct saa716x_adapter *adapter, int count) +{ + struct saa716x_dev *saa716x = adapter->saa716x; + struct saa716x_i2c *i2c = saa716x->i2c; + struct i2c_adapter *i2c_adapter = &i2c[SAA716x_I2C_BUS_A].i2c_adapter; + + dprintk(SAA716x_DEBUG, 1, "Adapter (%d) SAA716x frontend Init", count); + dprintk(SAA716x_DEBUG, 1, "Adapter (%d) Device ID=%02x", count, saa716x->pdev->subsystem_device); + + if (count == 0 || count == 1) { + adapter->fe = dvb_attach(stv090x_attach, + &tt6400_stv090x_config, + i2c_adapter, + STV090x_DEMODULATOR_0 + count); + + if (adapter->fe) { + struct stv6110x_devctl *ctl; + ctl = dvb_attach(stv6110x_attach, + adapter->fe, + &tt6400_stv6110x_config, + i2c_adapter); + + tt6400_stv090x_config.tuner_init = ctl->tuner_init; + tt6400_stv090x_config.tuner_sleep = ctl->tuner_sleep; + tt6400_stv090x_config.tuner_set_mode = ctl->tuner_set_mode; + tt6400_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency; + tt6400_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency; + tt6400_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth; + tt6400_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth; + tt6400_stv090x_config.tuner_set_bbgain = ctl->tuner_set_bbgain; + tt6400_stv090x_config.tuner_get_bbgain = ctl->tuner_get_bbgain; + tt6400_stv090x_config.tuner_set_refclk = ctl->tuner_set_refclk; + tt6400_stv090x_config.tuner_get_status = ctl->tuner_get_status; + + if (count == 1) { + /* call the init function once to initialize + tuner's clock output divider and demod's + master clock */ + /* The second tuner drives the STV0900 so + call it only for adapter 1 */ + if (adapter->fe->ops.init) + adapter->fe->ops.init(adapter->fe); + } + + dvb_attach(isl6423_attach, + adapter->fe, + i2c_adapter, + &tt6400_isl6423_config[count]); + + } + } + return 0; +} + +static struct saa716x_config saa716x_s26400_config = { + .model_name = SAA716x_MODEL_S2_6400_DUAL, + .dev_type = SAA716x_DEV_S2_6400_DUAL, + .boot_mode = SAA716x_EXT_BOOT, + .adapters = 2, + .frontend_attach = saa716x_s26400_frontend_attach, + .irq_handler = saa716x_ff_pci_irq, + .i2c_rate = SAA716x_I2C_RATE_100, + .i2c_mode = SAA716x_I2C_MODE_IRQ_BUFFERED, + + .adap_config = { + { + /* Adapter 0 */ + .ts_port = 2, + .worker = demux_worker + },{ + /* Adapter 1 */ + .ts_port = 3, + .worker = demux_worker + } + } +}; + + +static struct pci_device_id saa716x_ff_pci_table[] = { + + MAKE_ENTRY(TECHNOTREND, S2_6400_DUAL_S2_PREMIUM_DEVEL, SAA7160, &saa716x_s26400_config), /* S2 6400 Dual development version */ + MAKE_ENTRY(TECHNOTREND, S2_6400_DUAL_S2_PREMIUM_PROD, SAA7160, &saa716x_s26400_config), /* S2 6400 Dual production version */ + { } +}; +MODULE_DEVICE_TABLE(pci, saa716x_ff_pci_table); + +static struct pci_driver saa716x_ff_pci_driver = { + .name = DRIVER_NAME, + .id_table = saa716x_ff_pci_table, + .probe = saa716x_ff_pci_probe, + .remove = saa716x_ff_pci_remove, +}; + +static int saa716x_ff_init(void) +{ + return pci_register_driver(&saa716x_ff_pci_driver); +} + +static void saa716x_ff_exit(void) +{ + return pci_unregister_driver(&saa716x_ff_pci_driver); +} + +module_init(saa716x_ff_init); +module_exit(saa716x_ff_exit); + +MODULE_DESCRIPTION("SAA716x FF driver"); +MODULE_AUTHOR("Manu Abraham"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/common/saa716x/saa716x_fgpi.c b/drivers/media/common/saa716x/saa716x_fgpi.c new file mode 100644 index 0000000..8bdb13d --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_fgpi.c @@ -0,0 +1,389 @@ +#include + +#include "saa716x_mod.h" + +#include "saa716x_fgpi_reg.h" +#include "saa716x_dma_reg.h" +#include "saa716x_msi_reg.h" + +#include "saa716x_dma.h" +#include "saa716x_fgpi.h" +#include "saa716x_spi.h" +#include "saa716x_priv.h" + +static const u32 mmu_pta_base[] = { + MMU_PTA_BASE0, + MMU_PTA_BASE1, + MMU_PTA_BASE2, + MMU_PTA_BASE3, + MMU_PTA_BASE4, + MMU_PTA_BASE5, + MMU_PTA_BASE6, + MMU_PTA_BASE7, + MMU_PTA_BASE8, + MMU_PTA_BASE9, + MMU_PTA_BASE10, + MMU_PTA_BASE11, + MMU_PTA_BASE12, + MMU_PTA_BASE13, + MMU_PTA_BASE14, + MMU_PTA_BASE15, +}; + +static const u32 mmu_dma_cfg[] = { + MMU_DMA_CONFIG0, + MMU_DMA_CONFIG1, + MMU_DMA_CONFIG2, + MMU_DMA_CONFIG3, + MMU_DMA_CONFIG4, + MMU_DMA_CONFIG5, + MMU_DMA_CONFIG6, + MMU_DMA_CONFIG7, + MMU_DMA_CONFIG8, + MMU_DMA_CONFIG9, + MMU_DMA_CONFIG10, + MMU_DMA_CONFIG11, + MMU_DMA_CONFIG12, + MMU_DMA_CONFIG13, + MMU_DMA_CONFIG14, + MMU_DMA_CONFIG15, +}; + +static const u32 fgpi_ch[] = { + FGPI0, + FGPI1, + FGPI2, + FGPI3 +}; + +static const u32 bamdma_bufmode[] = { + BAM_FGPI0_DMA_BUF_MODE, + BAM_FGPI1_DMA_BUF_MODE, + BAM_FGPI2_DMA_BUF_MODE, + BAM_FGPI3_DMA_BUF_MODE +}; + +static const u32 msi_int_tagack[] = { + MSI_INT_TAGACK_FGPI_0, + MSI_INT_TAGACK_FGPI_1, + MSI_INT_TAGACK_FGPI_2, + MSI_INT_TAGACK_FGPI_3 +}; + +static const u32 msi_int_ovrflw[] = { + MSI_INT_OVRFLW_FGPI_0, + MSI_INT_OVRFLW_FGPI_1, + MSI_INT_OVRFLW_FGPI_2, + MSI_INT_OVRFLW_FGPI_3 +}; + +static const u32 msi_int_avint[] = { + MSI_INT_AVINT_FGPI_0, + MSI_INT_AVINT_FGPI_1, + MSI_INT_AVINT_FGPI_2, + MSI_INT_AVINT_FGPI_3 +}; + +void saa716x_fgpiint_disable(struct saa716x_dmabuf *dmabuf, int channel) +{ + struct saa716x_dev *saa716x = dmabuf->saa716x; + + u32 fgpi_port; + + fgpi_port = fgpi_ch[channel]; + + SAA716x_EPWR(fgpi_port, INT_ENABLE, 0); /* disable FGPI IRQ */ + SAA716x_EPWR(fgpi_port, INT_CLR_STATUS, 0x7f); /* clear status */ +} +EXPORT_SYMBOL_GPL(saa716x_fgpiint_disable); + +int saa716x_fgpi_get_write_index(struct saa716x_dev *saa716x, u32 fgpi_index) +{ + u32 fgpi_base; + u32 buf_mode_reg; + u32 buf_mode; + + switch (fgpi_index) { + case 0: /* FGPI_0 */ + fgpi_base = FGPI0; + buf_mode_reg = BAM_FGPI0_DMA_BUF_MODE; + break; + + case 1: /* FGPI_1 */ + fgpi_base = FGPI1; + buf_mode_reg = BAM_FGPI1_DMA_BUF_MODE; + break; + + case 2: /* FGPI_2 */ + fgpi_base = FGPI2; + buf_mode_reg = BAM_FGPI2_DMA_BUF_MODE; + break; + + case 3: /* FGPI_3 */ + fgpi_base = FGPI3; + buf_mode_reg = BAM_FGPI3_DMA_BUF_MODE; + break; + + default: + printk(KERN_ERR "%s: unexpected fgpi %u\n", + __func__, fgpi_index); + return -1; + } + + buf_mode = SAA716x_EPRD(BAM, buf_mode_reg); + if (saa716x->revision < 2) { + /* workaround for revision 1: restore buffer numbers on BAM */ + SAA716x_EPWR(fgpi_base, INT_CLR_STATUS, 0x7F); + SAA716x_EPWR(BAM, buf_mode_reg, buf_mode | 7); + } + return (buf_mode >> 3) & 0x7; +} +EXPORT_SYMBOL_GPL(saa716x_fgpi_get_write_index); + +static u32 saa716x_init_ptables(struct saa716x_dmabuf *dmabuf, int channel) +{ + struct saa716x_dev *saa716x = dmabuf->saa716x; + + u32 config, i; + + for (i = 0; i < FGPI_BUFFERS; i++) + BUG_ON((dmabuf[i].mem_ptab_phys == 0)); + + config = mmu_dma_cfg[channel]; /* DMACONFIGx */ + + SAA716x_EPWR(MMU, config, (FGPI_BUFFERS - 1)); + SAA716x_EPWR(MMU, MMU_PTA0_LSB(channel), PTA_LSB(dmabuf[0].mem_ptab_phys)); /* Low */ + SAA716x_EPWR(MMU, MMU_PTA0_MSB(channel), PTA_MSB(dmabuf[0].mem_ptab_phys)); /* High */ + SAA716x_EPWR(MMU, MMU_PTA1_LSB(channel), PTA_LSB(dmabuf[1].mem_ptab_phys)); /* Low */ + SAA716x_EPWR(MMU, MMU_PTA1_MSB(channel), PTA_MSB(dmabuf[1].mem_ptab_phys)); /* High */ + SAA716x_EPWR(MMU, MMU_PTA2_LSB(channel), PTA_LSB(dmabuf[2].mem_ptab_phys)); /* Low */ + SAA716x_EPWR(MMU, MMU_PTA2_MSB(channel), PTA_MSB(dmabuf[2].mem_ptab_phys)); /* High */ + SAA716x_EPWR(MMU, MMU_PTA3_LSB(channel), PTA_LSB(dmabuf[3].mem_ptab_phys)); /* Low */ + SAA716x_EPWR(MMU, MMU_PTA3_MSB(channel), PTA_MSB(dmabuf[3].mem_ptab_phys)); /* High */ + SAA716x_EPWR(MMU, MMU_PTA4_LSB(channel), PTA_LSB(dmabuf[4].mem_ptab_phys)); /* Low */ + SAA716x_EPWR(MMU, MMU_PTA4_MSB(channel), PTA_MSB(dmabuf[4].mem_ptab_phys)); /* High */ + SAA716x_EPWR(MMU, MMU_PTA5_LSB(channel), PTA_LSB(dmabuf[5].mem_ptab_phys)); /* Low */ + SAA716x_EPWR(MMU, MMU_PTA5_MSB(channel), PTA_MSB(dmabuf[5].mem_ptab_phys)); /* High */ + SAA716x_EPWR(MMU, MMU_PTA6_LSB(channel), PTA_LSB(dmabuf[6].mem_ptab_phys)); /* Low */ + SAA716x_EPWR(MMU, MMU_PTA6_MSB(channel), PTA_MSB(dmabuf[6].mem_ptab_phys)); /* High */ + SAA716x_EPWR(MMU, MMU_PTA7_LSB(channel), PTA_LSB(dmabuf[7].mem_ptab_phys)); /* Low */ + SAA716x_EPWR(MMU, MMU_PTA7_MSB(channel), PTA_MSB(dmabuf[7].mem_ptab_phys)); /* High */ + + return 0; +} + +int saa716x_fgpi_setparams(struct saa716x_dmabuf *dmabuf, + struct fgpi_stream_params *stream_params, + int port) +{ + struct saa716x_dev *saa716x = dmabuf->saa716x; + + u32 fgpi_port, buf_mode, val, mid; + u32 D1_XY_END, offst_1, offst_2; + int i = 0; + + fgpi_port = fgpi_ch[port]; + buf_mode = bamdma_bufmode[port]; + + /* Reset FGPI block */ + SAA716x_EPWR(fgpi_port, FGPI_SOFT_RESET, FGPI_SOFTWARE_RESET); + + /* Reset DMA channel */ + SAA716x_EPWR(BAM, buf_mode, 0x00000040); + saa716x_init_ptables(dmabuf, saa716x->fgpi[port].dma_channel); + + + /* monitor BAM reset */ + val = SAA716x_EPRD(BAM, buf_mode); + while (val && (i < 100)) { + msleep(30); + val = SAA716x_EPRD(BAM, buf_mode); + i++; + } + + if (val) { + dprintk(SAA716x_ERROR, 1, "Error: BAM FGPI Reset failed!"); + return -EIO; + } + + /* set buffer count */ + SAA716x_EPWR(BAM, buf_mode, FGPI_BUFFERS - 1); + + /* initialize all available address offsets */ + SAA716x_EPWR(BAM, BAM_FGPI_ADDR_OFFST_0(port), 0x0); + SAA716x_EPWR(BAM, BAM_FGPI_ADDR_OFFST_1(port), 0x0); + SAA716x_EPWR(BAM, BAM_FGPI_ADDR_OFFST_2(port), 0x0); + SAA716x_EPWR(BAM, BAM_FGPI_ADDR_OFFST_3(port), 0x0); + SAA716x_EPWR(BAM, BAM_FGPI_ADDR_OFFST_4(port), 0x0); + SAA716x_EPWR(BAM, BAM_FGPI_ADDR_OFFST_5(port), 0x0); + SAA716x_EPWR(BAM, BAM_FGPI_ADDR_OFFST_6(port), 0x0); + SAA716x_EPWR(BAM, BAM_FGPI_ADDR_OFFST_7(port), 0x0); + + /* get module ID */ + mid = SAA716x_EPRD(fgpi_port, FGPI_MODULE_ID); + if (mid != 0x14b0100) + dprintk(SAA716x_ERROR, 1, "FGPI Id<%04x> is not supported", mid); + + /* Initialize FGPI block */ + SAA716x_EPWR(fgpi_port, FGPI_REC_SIZE, stream_params->samples * (stream_params->bits / 8)); + SAA716x_EPWR(fgpi_port, FGPI_STRIDE, stream_params->pitch); + + offst_1 = 0; + offst_2 = 0; + switch (stream_params->stream_type) { + case FGPI_TRANSPORT_STREAM: + SAA716x_EPWR(fgpi_port, FGPI_CONTROL, 0x00000080); + SAA716x_EPWR(fgpi_port, FGPI_SIZE, stream_params->lines); + break; + + case FGPI_PROGRAM_STREAM: + SAA716x_EPWR(fgpi_port, FGPI_CONTROL, 0x00000088); + SAA716x_EPWR(fgpi_port, FGPI_SIZE, stream_params->lines); + break; + + case FGPI_VIDEO_STREAM: + SAA716x_EPWR(fgpi_port, FGPI_CONTROL, 0x00000088); + SAA716x_EPWR(fgpi_port, FGPI_D1_XY_START, 0x00000002); + + if ((stream_params->stream_flags & FGPI_INTERLACED) && + (stream_params->stream_flags & FGPI_ODD_FIELD) && + (stream_params->stream_flags & FGPI_EVEN_FIELD)) { + + SAA716x_EPWR(fgpi_port, FGPI_SIZE, stream_params->lines / 2); + SAA716x_EPWR(fgpi_port, FGPI_STRIDE, 768 * 4); /* interlaced stride of 2 lines */ + + D1_XY_END = (stream_params->samples << 16); + D1_XY_END |= (stream_params->lines / 2) + 2; + + if (stream_params->stream_flags & FGPI_PAL) + offst_1 = 768 * 2; + else + offst_2 = 768 * 2; + + } else { + SAA716x_EPWR(fgpi_port, FGPI_SIZE, stream_params->lines); + SAA716x_EPWR(fgpi_port, FGPI_STRIDE, 768 * 2); /* stride of 1 line */ + + D1_XY_END = stream_params->samples << 16; + D1_XY_END |= stream_params->lines + 2; + } + + SAA716x_EPWR(fgpi_port, FGPI_D1_XY_END, D1_XY_END); + break; + + default: + SAA716x_EPWR(fgpi_port, FGPI_CONTROL, 0x00000080); + break; + } + + SAA716x_EPWR(fgpi_port, FGPI_BASE_1, ((saa716x->fgpi[port].dma_channel) << 21) + offst_1); + SAA716x_EPWR(fgpi_port, FGPI_BASE_2, ((saa716x->fgpi[port].dma_channel) << 21) + offst_2); + + return 0; +} + +int saa716x_fgpi_start(struct saa716x_dev *saa716x, int port, + struct fgpi_stream_params *stream_params) +{ + u32 fgpi_port; + u32 config; + u32 val; + u32 i; + + fgpi_port = fgpi_ch[port]; + + SAA716x_EPWR(fgpi_port, FGPI_INTERFACE, 0); + msleep(10); + + if (saa716x_fgpi_setparams(saa716x->fgpi[port].dma_buf, stream_params, port) != 0) { + return -EIO; + } + + config = mmu_dma_cfg[saa716x->fgpi[port].dma_channel]; /* DMACONFIGx */ + + val = SAA716x_EPRD(MMU, config); + SAA716x_EPWR(MMU, config, val & ~0x40); + SAA716x_EPWR(MMU, config, val | 0x40); + + SAA716x_EPWR(fgpi_port, INT_ENABLE, 0x7F); + + val = SAA716x_EPRD(MMU, config); + i = 0; + while (i < 500) { + if (val & 0x80) + break; + msleep(10); + val = SAA716x_EPRD(MMU, config); + i++; + } + + if (!(val & 0x80)) { + dprintk(SAA716x_ERROR, 1, "Error: PTE pre-fetch failed!"); + return -EIO; + } + + val = SAA716x_EPRD(fgpi_port, FGPI_CONTROL); + val |= 0x3000; + + saa716x_set_clk_external(saa716x, saa716x->fgpi[port].dma_channel); + + SAA716x_EPWR(fgpi_port, FGPI_CONTROL, val); + + SAA716x_EPWR(MSI, MSI_INT_ENA_SET_L, msi_int_tagack[port]); + + return 0; +} + +int saa716x_fgpi_stop(struct saa716x_dev *saa716x, int port) +{ + u32 fgpi_port; + u32 val; + + fgpi_port = fgpi_ch[port]; + + SAA716x_EPWR(MSI, MSI_INT_ENA_CLR_L, msi_int_tagack[port]); + + val = SAA716x_EPRD(fgpi_port, FGPI_CONTROL); + val &= ~0x3000; + SAA716x_EPWR(fgpi_port, FGPI_CONTROL, val); + + saa716x_set_clk_internal(saa716x, saa716x->fgpi[port].dma_channel); + + return 0; +} + +int saa716x_fgpi_init(struct saa716x_dev *saa716x, int port, + void (*worker)(unsigned long)) +{ + int i; + int ret; + + saa716x->fgpi[port].dma_channel = port + 6; + for (i = 0; i < FGPI_BUFFERS; i++) + { + /* TODO: what is a good size for TS DMA buffer? */ + ret = saa716x_dmabuf_alloc(saa716x, &saa716x->fgpi[port].dma_buf[i], 16 * SAA716x_PAGE_SIZE); + if (ret < 0) { + return ret; + } + } + saa716x->fgpi[port].saa716x = saa716x; + tasklet_init(&saa716x->fgpi[port].tasklet, worker, + (unsigned long)&saa716x->fgpi[port]); + saa716x->fgpi[port].read_index = 0; + + return 0; +} + +int saa716x_fgpi_exit(struct saa716x_dev *saa716x, int port) +{ + int i; + + tasklet_kill(&saa716x->fgpi[port].tasklet); + for (i = 0; i < FGPI_BUFFERS; i++) + { + saa716x_dmabuf_free(saa716x, &saa716x->fgpi[port].dma_buf[i]); + } + + return 0; +} diff --git a/drivers/media/common/saa716x/saa716x_fgpi.h b/drivers/media/common/saa716x/saa716x_fgpi.h new file mode 100644 index 0000000..225aff0 --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_fgpi.h @@ -0,0 +1,112 @@ +#ifndef __SAA716x_FGPI_H +#define __SAA716x_FGPI_H + +#include + +#define FGPI_BUFFERS 8 +#define PTA_LSB(__mem) ((u32 ) (__mem)) +#define PTA_MSB(__mem) ((u32 ) ((u64)(__mem) >> 32)) + +#define BAM_DMA_BUF_MODE_BASE 0x0d8 +#define BAM_DMA_BUF_MODE_OFFSET 0x24 + +#define BAM_DMA_BUF_MODE(__ch) (BAM_DMA_BUF_MODE_BASE + (BAM_DMA_BUF_MODE_OFFSET * __ch)) + +#define BAM_FGPI_ADDR_OFFST_BASE 0x0dc +#define BAM_FGPI_ADDR_OFFST_OFFSET 0x24 + +#define BAM_FGPI_ADDR_OFFSET(__ch) (BAM_FGPI_ADDR_OFFST_BASE + (BAM_FGPI_ADDR_OFFST_OFFSET * __ch)) + +#define BAM_FGPI_ADDR_OFFST_0(__ch) BAM_FGPI_ADDR_OFFSET(__ch) + 0x00 +#define BAM_FGPI_ADDR_OFFST_1(__ch) BAM_FGPI_ADDR_OFFSET(__ch) + 0x04 +#define BAM_FGPI_ADDR_OFFST_2(__ch) BAM_FGPI_ADDR_OFFSET(__ch) + 0x08 +#define BAM_FGPI_ADDR_OFFST_3(__ch) BAM_FGPI_ADDR_OFFSET(__ch) + 0x0c +#define BAM_FGPI_ADDR_OFFST_4(__ch) BAM_FGPI_ADDR_OFFSET(__ch) + 0x10 +#define BAM_FGPI_ADDR_OFFST_5(__ch) BAM_FGPI_ADDR_OFFSET(__ch) + 0x14 +#define BAM_FGPI_ADDR_OFFST_6(__ch) BAM_FGPI_ADDR_OFFSET(__ch) + 0x18 +#define BAM_FGPI_ADDR_OFFST_7(__ch) BAM_FGPI_ADDR_OFFSET(__ch) + 0x1c + +struct saa716x_dmabuf; + +/* + * Port supported streams + * + * FGPI_AUDIO_STREAM + * FGPI_VIDEO_STREAM + * FGPI_VBI_STREAM + * FGPI_TRANSPORT_STREAM + * FGPI_PROGRAM_STREAM + */ +enum fgpi_stream_type { + FGPI_AUDIO_STREAM = 0x01, + FGPI_VIDEO_STREAM = 0x02, + FGPI_VBI_STREAM = 0x04, + FGPI_TRANSPORT_STREAM = 0x08, + FGPI_PROGRAM_STREAM = 0x10 +}; + +/* + * Stream port flags + * + * FGPI_ODD_FIELD + * FGPI_EVEN_FIELD + * FGPI_HD_0 + * FGPI_HD_1 + * FGPI_PAL + * FGPI_NTSC + */ +enum fgpi_stream_flags { + FGPI_ODD_FIELD = 0x0001, + FGPI_EVEN_FIELD = 0x0002, + FGPI_INTERLACED = 0x0004, + FGPI_HD0 = 0x0010, + FGPI_HD1 = 0x0020, + FGPI_PAL = 0x0040, + FGPI_NTSC = 0x0080, + FGPI_NO_SCALER = 0x0100, +}; + +/* + * Stream port parameters + * bits: Bits per sample + * samples: samples perline + * lines: number of lines + * pitch: stream pitch in bytes + * offset: offset to first valid line + */ +struct fgpi_stream_params { + u32 bits; + u32 samples; + u32 lines; + + s32 pitch; + + u32 offset; + u32 page_tables; + + enum fgpi_stream_flags stream_flags; + enum fgpi_stream_type stream_type; +}; + +struct saa716x_dmabuf; + +struct saa716x_fgpi_stream_port { + u8 dma_channel; + struct saa716x_dmabuf dma_buf[FGPI_BUFFERS]; + struct saa716x_dev *saa716x; + struct tasklet_struct tasklet; + u8 read_index; +}; + +extern void saa716x_fgpiint_disable(struct saa716x_dmabuf *dmabuf, int channel); +extern int saa716x_fgpi_get_write_index(struct saa716x_dev *saa716x, + u32 fgpi_index); +extern int saa716x_fgpi_start(struct saa716x_dev *saa716x, int port, + struct fgpi_stream_params *stream_params); +extern int saa716x_fgpi_stop(struct saa716x_dev *saa716x, int port); + +extern int saa716x_fgpi_init(struct saa716x_dev *saa716x, int port, + void (*worker)(unsigned long)); +extern int saa716x_fgpi_exit(struct saa716x_dev *saa716x, int port); + +#endif /* __SAA716x_FGPI_H */ diff --git a/drivers/media/common/saa716x/saa716x_fgpi_reg.h b/drivers/media/common/saa716x/saa716x_fgpi_reg.h new file mode 100644 index 0000000..1193016 --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_fgpi_reg.h @@ -0,0 +1,74 @@ +#ifndef __SAA716x_FGPI_REG_H +#define __SAA716x_FGPI_REG_H + +/* -------------- FGPI Registers -------------- */ + +#define FGPI_CONTROL 0x000 +#define FGPI_CAPTURE_ENABLE_2 (0x00000001 << 13) +#define FGPI_CAPTURE_ENABLE_1 (0x00000001 << 12) +#define FGPI_MODE (0x00000001 << 11) +#define FGPI_SAMPLE_SIZE (0x00000003 << 8) +#define FGPI_BUF_SYNC_MSG_STOP (0x00000003 << 5) +#define FGPI_REC_START_MSG_START (0x00000003 << 2) +#define FGPI_TSTAMP_SELECT (0x00000001 << 1) +#define FGPI_VAR_LENGTH (0x00000001 << 0) + +#define FGPI_BASE_1 0x004 +#define FGPI_BASE_2 0x008 +#define FGPI_SIZE 0x00c +#define FGPI_REC_SIZE 0x010 +#define FGPI_STRIDE 0x014 +#define FGPI_NUM_RECORD_1 0x018 +#define FGPI_NUM_RECORD_2 0x01c +#define FGPI_THRESHOLD_1 0x020 +#define FGPI_THRESHOLD_2 0x024 +#define FGPI_D1_XY_START 0x028 +#define FGPI_D1_XY_END 0x02c + +#define INT_STATUS 0xfe0 +#define FGPI_BUF1_ACTIVE (0x00000001 << 7) +#define FGPI_OVERFLOW (0x00000001 << 6) +#define FGPI_MBE (0x00000001 << 5) +#define FGPI_UNDERRUN (0x00000001 << 4) +#define FGPI_THRESH2_REACHED (0x00000001 << 3) +#define FGPI_THRESH1_REACHED (0x00000001 << 2) +#define FGPI_BUF2_FULL (0x00000001 << 1) +#define FGPI_BUF1_FULL (0x00000001 << 0) + +#define INT_ENABLE 0xfe4 +#define FGPI_OVERFLOW_ENA (0x00000001 << 6) +#define FGPI_MBE_ENA (0x00000001 << 5) +#define FGPI_UNDERRUN_ENA (0x00000001 << 4) +#define FGPI_THRESH2_REACHED_ENA (0x00000001 << 3) +#define FGPI_THRESH1_REACHED_ENA (0x00000001 << 2) +#define FGPI_BUF2_FULL_ENA (0x00000001 << 1) +#define FGPI_BUF1_FULL_ENA (0x00000001 << 0) + +#define INT_CLR_STATUS 0xfe8 +#define FGPI_OVERFLOW_ACK (0x00000001 << 6) +#define FGPI_MBE_ACK (0x00000001 << 5) +#define FGPI_UNDERRUN_ACK (0x00000001 << 4) +#define FGPI_THRESH2_REACHED_ACK (0x00000001 << 3) +#define FGPI_THRESH1_REACHED_ACK (0x00000001 << 2) +#define FGPI_BUF2_DONE_ACK (0x00000001 << 1) +#define FGPI_BUF1_DONE_ACK (0x00000001 << 0) + +#define INT_SET_STATUS 0xfec +#define FGPI_OVERFLOW_SET (0x00000001 << 6) +#define FGPI_MBE_SET (0x00000001 << 5) +#define FGPI_UNDERRUN_SET (0x00000001 << 4) +#define FGPI_THRESH2_REACHED_SET (0x00000001 << 3) +#define FGPI_THRESH1_REACHED_SET (0x00000001 << 2) +#define FGPI_BUF2_DONE_SET (0x00000001 << 1) +#define FGPI_BUF1_DONE_SET (0x00000001 << 0) + +#define FGPI_SOFT_RESET 0xff0 +#define FGPI_SOFTWARE_RESET (0x00000001 << 0) + +#define FGPI_INTERFACE 0xff4 +#define FGPI_DISABLE_BUS_IF (0x00000001 << 0) + +#define FGPI_MOD_ID_EXT 0xff8 +#define FGPI_MODULE_ID 0xffc + +#endif /* __SAA716x_FGPI_REG_H */ diff --git a/drivers/media/common/saa716x/saa716x_gpio.c b/drivers/media/common/saa716x/saa716x_gpio.c new file mode 100644 index 0000000..62b6112 --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_gpio.c @@ -0,0 +1,140 @@ +#include +#include + +#include "saa716x_mod.h" + +#include "saa716x_gpio_reg.h" + +#include "saa716x_gpio.h" +#include "saa716x_spi.h" +#include "saa716x_priv.h" + +void saa716x_gpio_init(struct saa716x_dev *saa716x) +{ + spin_lock_init(&saa716x->gpio_lock); +} +EXPORT_SYMBOL_GPL(saa716x_gpio_init); + +int saa716x_get_gpio_mode(struct saa716x_dev *saa716x, u32 *config) +{ + *config = SAA716x_EPRD(GPIO, GPIO_WR_MODE); + + return 0; +} + +int saa716x_set_gpio_mode(struct saa716x_dev *saa716x, u32 mask, u32 config) +{ + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&saa716x->gpio_lock, flags); + reg = SAA716x_EPRD(GPIO, GPIO_WR_MODE); + reg &= ~mask; + reg |= (config & mask); + SAA716x_EPWR(GPIO, GPIO_WR_MODE, reg); + spin_unlock_irqrestore(&saa716x->gpio_lock, flags); + + return 0; +} + +u32 saa716x_gpio_rd(struct saa716x_dev *saa716x) +{ + return SAA716x_EPRD(GPIO, GPIO_RD); +} + +void saa716x_gpio_wr(struct saa716x_dev *saa716x, u32 data) +{ + SAA716x_EPWR(GPIO, GPIO_WR, data); +} + +void saa716x_gpio_ctl(struct saa716x_dev *saa716x, u32 mask, u32 bits) +{ + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&saa716x->gpio_lock, flags); + + reg = SAA716x_EPRD(GPIO, GPIO_OEN); + reg &= mask; + reg |= bits; + SAA716x_EPWR(GPIO, GPIO_OEN, reg); + + spin_unlock_irqrestore(&saa716x->gpio_lock, flags); +} + +void saa716x_gpio_bits(struct saa716x_dev *saa716x, u32 bits) +{ + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&saa716x->gpio_lock, flags); + + reg = SAA716x_EPRD(GPIO, GPIO_WR); + reg &= ~bits; + /* TODO ! add maskable config bits in here */ + /* reg |= (config->mask & bits) */ + reg |= bits; + SAA716x_EPWR(GPIO, GPIO_WR, reg); + + spin_unlock_irqrestore(&saa716x->gpio_lock, flags); +} + +void saa716x_gpio_set_output(struct saa716x_dev *saa716x, int gpio) +{ + uint32_t value; + + value = SAA716x_EPRD(GPIO, GPIO_OEN); + value &= ~(1 << gpio); + SAA716x_EPWR(GPIO, GPIO_OEN, value); +} +EXPORT_SYMBOL_GPL(saa716x_gpio_set_output); + +void saa716x_gpio_set_input(struct saa716x_dev *saa716x, int gpio) +{ + uint32_t value; + + value = SAA716x_EPRD(GPIO, GPIO_OEN); + value |= 1 << gpio; + SAA716x_EPWR(GPIO, GPIO_OEN, value); +} +EXPORT_SYMBOL_GPL(saa716x_gpio_set_input); + +void saa716x_gpio_set_mode(struct saa716x_dev *saa716x, int gpio, int mode) +{ + uint32_t value; + + value = SAA716x_EPRD(GPIO, GPIO_WR_MODE); + if (mode) + value |= 1 << gpio; + else + value &= ~(1 << gpio); + SAA716x_EPWR(GPIO, GPIO_WR_MODE, value); +} +EXPORT_SYMBOL_GPL(saa716x_gpio_set_mode); + +void saa716x_gpio_write(struct saa716x_dev *saa716x, int gpio, int set) +{ + uint32_t value; + unsigned long flags; + + spin_lock_irqsave(&saa716x->gpio_lock, flags); + value = SAA716x_EPRD(GPIO, GPIO_WR); + if (set) + value |= 1 << gpio; + else + value &= ~(1 << gpio); + SAA716x_EPWR(GPIO, GPIO_WR, value); + spin_unlock_irqrestore(&saa716x->gpio_lock, flags); +} +EXPORT_SYMBOL_GPL(saa716x_gpio_write); + +int saa716x_gpio_read(struct saa716x_dev *saa716x, int gpio) +{ + uint32_t value; + + value = SAA716x_EPRD(GPIO, GPIO_RD); + if (value & (1 << gpio)) + return 1; + return 0; +} +EXPORT_SYMBOL_GPL(saa716x_gpio_read); diff --git a/drivers/media/common/saa716x/saa716x_gpio.h b/drivers/media/common/saa716x/saa716x_gpio.h new file mode 100644 index 0000000..a82580b --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_gpio.h @@ -0,0 +1,26 @@ +#ifndef __SAA716x_GPIO_H +#define __SAA716x_GPIO_H + +#define BOOT_MODE GPIO_31 | GPIO_30 +#define AV_UNIT_B GPIO_25 +#define AV_UNIT_A GPIO_24 +#define AV_INTR_B GPIO_01 +#define AV_INTR_A GPIO_00 + +struct saa716x_dev; + +extern void saa716x_gpio_init(struct saa716x_dev *saa716x); + +extern u32 saa716x_gpio_rd(struct saa716x_dev *saa716x); +extern void saa716x_gpio_wr(struct saa716x_dev *saa716x, u32 data); +extern void saa716x_gpio_ctl(struct saa716x_dev *saa716x, u32 mask, u32 bits); + +extern void saa716x_gpio_bits(struct saa716x_dev *saa716x, u32 bits); + +extern void saa716x_gpio_set_output(struct saa716x_dev *saa716x, int gpio); +extern void saa716x_gpio_set_input(struct saa716x_dev *saa716x, int gpio); +extern void saa716x_gpio_set_mode(struct saa716x_dev *saa716x, int gpio, int mode); +extern void saa716x_gpio_write(struct saa716x_dev *saa716x, int gpio, int set); +extern int saa716x_gpio_read(struct saa716x_dev *saa716x, int gpio); + +#endif /* __SAA716x_GPIO_H */ diff --git a/drivers/media/common/saa716x/saa716x_gpio_reg.h b/drivers/media/common/saa716x/saa716x_gpio_reg.h new file mode 100644 index 0000000..f36184a --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_gpio_reg.h @@ -0,0 +1,47 @@ +#ifndef __SAA716x_GPIO_REG_H +#define __SAA716x_GPIO_REG_H + +/* -------------- GPIO Registers -------------- */ + +#define GPIO_RD 0x000 +#define GPIO_WR 0x004 +#define GPIO_WR_MODE 0x008 +#define GPIO_OEN 0x00c + +#define GPIO_SW_RST 0xff0 +#define GPIO_SW_RESET (0x00000001 << 0) + +#define GPIO_31 (1 << 31) +#define GPIO_30 (1 << 30) +#define GPIO_29 (1 << 29) +#define GPIO_28 (1 << 28) +#define GPIO_27 (1 << 27) +#define GPIO_26 (1 << 26) +#define GPIO_25 (1 << 25) +#define GPIO_24 (1 << 24) +#define GPIO_23 (1 << 23) +#define GPIO_22 (1 << 22) +#define GPIO_21 (1 << 21) +#define GPIO_20 (1 << 20) +#define GPIO_19 (1 << 19) +#define GPIO_18 (1 << 18) +#define GPIO_17 (1 << 17) +#define GPIO_16 (1 << 16) +#define GPIO_15 (1 << 15) +#define GPIO_14 (1 << 14) +#define GPIO_13 (1 << 13) +#define GPIO_12 (1 << 12) +#define GPIO_11 (1 << 11) +#define GPIO_10 (1 << 10) +#define GPIO_09 (1 << 9) +#define GPIO_08 (1 << 8) +#define GPIO_07 (1 << 7) +#define GPIO_06 (1 << 6) +#define GPIO_05 (1 << 5) +#define GPIO_04 (1 << 4) +#define GPIO_03 (1 << 3) +#define GPIO_02 (1 << 2) +#define GPIO_01 (1 << 1) +#define GPIO_00 (1 << 0) + +#endif /* __SAA716x_GPIO_REG_H */ diff --git a/drivers/media/common/saa716x/saa716x_greg.c b/drivers/media/common/saa716x/saa716x_greg.c new file mode 100644 index 0000000..d93a3b8 --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_greg.c @@ -0,0 +1,42 @@ +#include + +#include "saa716x_mod.h" + +#include "saa716x_greg_reg.h" +#include "saa716x_greg.h" +#include "saa716x_spi.h" +#include "saa716x_priv.h" + +static u32 g_save[12]; + +void saa716x_greg_save(struct saa716x_dev *saa716x) +{ + g_save[0] = SAA716x_EPRD(GREG, GREG_SUBSYS_CONFIG); + g_save[1] = SAA716x_EPRD(GREG, GREG_MSI_BAR_PMCSR); + g_save[2] = SAA716x_EPRD(GREG, GREG_PMCSR_DATA_1); + g_save[3] = SAA716x_EPRD(GREG, GREG_PMCSR_DATA_2); + g_save[4] = SAA716x_EPRD(GREG, GREG_VI_CTRL); + g_save[5] = SAA716x_EPRD(GREG, GREG_FGPI_CTRL); + g_save[6] = SAA716x_EPRD(GREG, GREG_RSTU_CTRL); + g_save[7] = SAA716x_EPRD(GREG, GREG_I2C_CTRL); + g_save[8] = SAA716x_EPRD(GREG, GREG_OVFLW_CTRL); + g_save[9] = SAA716x_EPRD(GREG, GREG_TAG_ACK_FLEN); + + g_save[10] = SAA716x_EPRD(GREG, GREG_VIDEO_IN_CTRL); +} + +void saa716x_greg_restore(struct saa716x_dev *saa716x) +{ + SAA716x_EPWR(GREG, GREG_SUBSYS_CONFIG, g_save[0]); + SAA716x_EPWR(GREG, GREG_MSI_BAR_PMCSR, g_save[1]); + SAA716x_EPWR(GREG, GREG_PMCSR_DATA_1, g_save[2]); + SAA716x_EPWR(GREG, GREG_PMCSR_DATA_2, g_save[3]); + SAA716x_EPWR(GREG, GREG_VI_CTRL, g_save[4]); + SAA716x_EPWR(GREG, GREG_FGPI_CTRL, g_save[5]); + SAA716x_EPWR(GREG, GREG_RSTU_CTRL, g_save[6]); + SAA716x_EPWR(GREG, GREG_I2C_CTRL, g_save[7]); + SAA716x_EPWR(GREG, GREG_OVFLW_CTRL, g_save[8]); + SAA716x_EPWR(GREG, GREG_TAG_ACK_FLEN, g_save[9]); + + SAA716x_EPWR(GREG, GREG_VIDEO_IN_CTRL, g_save[10]); +} diff --git a/drivers/media/common/saa716x/saa716x_greg.h b/drivers/media/common/saa716x/saa716x_greg.h new file mode 100644 index 0000000..487595e --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_greg.h @@ -0,0 +1,9 @@ +#ifndef __SAA716x_GREG_H +#define __SAA716x_GREG_H + +struct saa716x_dev; + +extern void saa716x_greg_save(struct saa716x_dev *saa716x); +extern void saa716x_greg_restore(struct saa716x_dev *saa716x); + +#endif /* __SAA716x_GREG_H */ diff --git a/drivers/media/common/saa716x/saa716x_greg_reg.h b/drivers/media/common/saa716x/saa716x_greg_reg.h new file mode 100644 index 0000000..052e8cd --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_greg_reg.h @@ -0,0 +1,91 @@ +#ifndef __SAA716x_GREG_REG_H +#define __SAA716x_GREG_REG_H + +/* -------------- GREG Registers -------------- */ + +#define GREG_SUBSYS_CONFIG 0x000 +#define GREG_SUBSYS_ID (0x0000ffff << 16) +#define GREG_SUBSYS_VID (0x0000ffff << 0) + +#define GREG_MSI_BAR_PMCSR 0x004 +#define GREG_PMCSR_SCALE_7 (0x00000003 << 30) +#define GREG_PMCSR_SCALE_6 (0x00000003 << 28) +#define GREG_PMCSR_SCALE_5 (0x00000003 << 26) +#define GREG_PMCSR_SCALE_4 (0x00000003 << 24) +#define GREG_PMCSR_SCALE_3 (0x00000003 << 22) +#define GREG_PMCSR_SCALE_2 (0x00000003 << 20) +#define GREG_PMCSR_SCALE_1 (0x00000003 << 18) +#define GREG_PMCSR_SCALE_0 (0x00000003 << 16) + +#define GREG_BAR_WIDTH_17 (0x0000001e << 8) +#define GREG_BAR_WIDTH_18 (0x0000001c << 8) +#define GREG_BAR_WIDTH_19 (0x00000018 << 8) +#define GREG_BAR_WIDTH_20 (0x00000010 << 8) + +#define GREG_BAR_PREFETCH (0x00000001 << 3) +#define GREG_MSI_MM_CAP1 (0x00000000 << 0) // FIXME ! +#define GREG_MSI_MM_CAP2 (0x00000001 << 0) +#define GREG_MSI_MM_CAP4 (0x00000002 << 0) +#define GREG_MSI_MM_CAP8 (0x00000003 << 0) +#define GREG_MSI_MM_CAP16 (0x00000004 << 0) +#define GREG_MSI_MM_CAP32 (0x00000005 << 0) + +#define GREG_PMCSR_DATA_1 0x008 +#define GREG_PMCSR_DATA_2 0x00c +#define GREG_VI_CTRL 0x010 +#define GREG_FGPI_CTRL 0x014 + +#define GREG_RSTU_CTRL 0x018 +#define GREG_BOOT_READY (0x00000001 << 13) +#define GREG_RESET_REQ (0x00000001 << 12) +#define GREG_IP_RST_RELEASE (0x00000001 << 11) +#define GREG_ADAPTER_RST_RELEASE (0x00000001 << 10) +#define GREG_PCIE_CORE_RST_RELEASE (0x00000001 << 9) +#define GREG_BOOT_IP_RST_RELEASE (0x00000001 << 8) +#define GREG_BOOT_RST_RELEASE (0x00000001 << 7) +#define GREG_CGU_RST_RELEASE (0x00000001 << 6) +#define GREG_IP_RST_ASSERT (0x00000001 << 5) +#define GREG_ADAPTER_RST_ASSERT (0x00000001 << 4) +#define GREG_RST_ASSERT (0x00000001 << 3) +#define GREG_BOOT_IP_RST_ASSERT (0x00000001 << 2) +#define GREG_BOOT_RST_ASSERT (0x00000001 << 1) +#define GREG_CGU_RST_ASSERT (0x00000001 << 0) + +#define GREG_I2C_CTRL 0x01c +#define GREG_I2C_SLAVE_ADDR (0x0000007f << 0) + +#define GREG_OVFLW_CTRL 0x020 +#define GREG_OVERFLOW_ENABLE (0x00001fff << 0) + +#define GREG_TAG_ACK_FLEN 0x024 +#define GREG_TAG_ACK_FLEN_1B (0x00000000 << 0) +#define GREG_TAG_ACK_FLEN_2B (0x00000001 << 0) +#define GREG_TAG_ACK_FLEN_4B (0x00000002 << 0) +#define GREG_TAG_ACK_FLEN_8B (0x00000003 << 0) + +#define GREG_VIDEO_IN_CTRL 0x028 + +#define GREG_SPARE_1 0x02c +#define GREG_SPARE_2 0x030 +#define GREG_SPARE_3 0x034 +#define GREG_SPARE_4 0x038 +#define GREG_SPARE_5 0x03c +#define GREG_SPARE_6 0x040 +#define GREG_SPARE_7 0x044 +#define GREG_SPARE_8 0x048 +#define GREG_SPARE_9 0x04c +#define GREG_SPARE_10 0x050 +#define GREG_SPARE_11 0x054 +#define GREG_SPARE_12 0x058 +#define GREG_SPARE_13 0x05c +#define GREG_SPARE_14 0x060 +#define GREG_SPARE_15 0x064 + +#define GREG_FAIL_DISABLE 0x068 +#define GREG_BOOT_FAIL_DISABLE (0x00000001 << 0) + +#define GREG_SW_RST 0xff0 +#define GREG_SW_RESET (0x00000001 << 0) + + +#endif /* __SAA716x_GREG_REG_H */ diff --git a/drivers/media/common/saa716x/saa716x_hybrid.c b/drivers/media/common/saa716x/saa716x_hybrid.c new file mode 100644 index 0000000..27e5e71 --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_hybrid.c @@ -0,0 +1,726 @@ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "saa716x_mod.h" + +#include "saa716x_gpio_reg.h" +#include "saa716x_greg_reg.h" +#include "saa716x_msi_reg.h" + +#include "saa716x_adap.h" +#include "saa716x_i2c.h" +#include "saa716x_msi.h" +#include "saa716x_hybrid.h" +#include "saa716x_gpio.h" +#include "saa716x_rom.h" +#include "saa716x_spi.h" +#include "saa716x_priv.h" + +#include "zl10353.h" +#include "mb86a16.h" +#include "tda1004x.h" +#include "tda827x.h" + +unsigned int verbose; +module_param(verbose, int, 0644); +MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)"); + +unsigned int int_type; +module_param(int_type, int, 0644); +MODULE_PARM_DESC(int_type, "force Interrupt Handler type: 0=INT-A, 1=MSI, 2=MSI-X. default INT-A mode"); + +#define DRIVER_NAME "SAA716x Hybrid" + +static int saa716x_hybrid_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) +{ + struct saa716x_dev *saa716x; + int err = 0; + + saa716x = kzalloc(sizeof (struct saa716x_dev), GFP_KERNEL); + if (saa716x == NULL) { + printk(KERN_ERR "saa716x_hybrid_pci_probe ERROR: out of memory\n"); + err = -ENOMEM; + goto fail0; + } + + saa716x->verbose = verbose; + saa716x->int_type = int_type; + saa716x->pdev = pdev; + saa716x->config = (struct saa716x_config *) pci_id->driver_data; + + err = saa716x_pci_init(saa716x); + if (err) { + dprintk(SAA716x_ERROR, 1, "SAA716x PCI Initialization failed"); + goto fail1; + } + + err = saa716x_cgu_init(saa716x); + if (err) { + dprintk(SAA716x_ERROR, 1, "SAA716x CGU Init failed"); + goto fail1; + } + + err = saa716x_core_boot(saa716x); + if (err) { + dprintk(SAA716x_ERROR, 1, "SAA716x Core Boot failed"); + goto fail2; + } + dprintk(SAA716x_DEBUG, 1, "SAA716x Core Boot Success"); + + err = saa716x_msi_init(saa716x); + if (err) { + dprintk(SAA716x_ERROR, 1, "SAA716x MSI Init failed"); + goto fail2; + } + + err = saa716x_jetpack_init(saa716x); + if (err) { + dprintk(SAA716x_ERROR, 1, "SAA716x Jetpack core Initialization failed"); + goto fail1; + } + + err = saa716x_i2c_init(saa716x); + if (err) { + dprintk(SAA716x_ERROR, 1, "SAA716x I2C Initialization failed"); + goto fail3; + } + + saa716x_gpio_init(saa716x); + + err = saa716x_dump_eeprom(saa716x); + if (err) { + dprintk(SAA716x_ERROR, 1, "SAA716x EEPROM dump failed"); + } + + err = saa716x_eeprom_data(saa716x); + if (err) { + dprintk(SAA716x_ERROR, 1, "SAA716x EEPROM dump failed"); + } + + /* enable decoders on 7162 */ + if (pdev->device == SAA7162) { + saa716x_gpio_set_output(saa716x, 24); + saa716x_gpio_set_output(saa716x, 25); + + saa716x_gpio_write(saa716x, 24, 0); + saa716x_gpio_write(saa716x, 25, 0); + + msleep(10); + + saa716x_gpio_write(saa716x, 24, 1); + saa716x_gpio_write(saa716x, 25, 1); + } + + /* set default port mapping */ + SAA716x_EPWR(GREG, GREG_VI_CTRL, 0x2C688F44); + /* enable FGPI3 and FGPI0 for TS input from Port 3 and 6 */ + SAA716x_EPWR(GREG, GREG_FGPI_CTRL, 0x894); + + err = saa716x_dvb_init(saa716x); + if (err) { + dprintk(SAA716x_ERROR, 1, "SAA716x DVB initialization failed"); + goto fail4; + } + + return 0; + +fail4: + saa716x_dvb_exit(saa716x); +fail3: + saa716x_i2c_exit(saa716x); +fail2: + saa716x_pci_exit(saa716x); +fail1: + kfree(saa716x); +fail0: + return err; +} + +static void saa716x_hybrid_pci_remove(struct pci_dev *pdev) +{ + struct saa716x_dev *saa716x = pci_get_drvdata(pdev); + + saa716x_dvb_exit(saa716x); + saa716x_i2c_exit(saa716x); + saa716x_pci_exit(saa716x); + kfree(saa716x); +} + +static irqreturn_t saa716x_hybrid_pci_irq(int irq, void *dev_id) +{ + struct saa716x_dev *saa716x = (struct saa716x_dev *) dev_id; + + u32 stat_h, stat_l, mask_h, mask_l; + + if (unlikely(saa716x == NULL)) { + printk("%s: saa716x=NULL", __func__); + return IRQ_NONE; + } + + stat_l = SAA716x_EPRD(MSI, MSI_INT_STATUS_L); + stat_h = SAA716x_EPRD(MSI, MSI_INT_STATUS_H); + mask_l = SAA716x_EPRD(MSI, MSI_INT_ENA_L); + mask_h = SAA716x_EPRD(MSI, MSI_INT_ENA_H); + + dprintk(SAA716x_DEBUG, 1, "MSI STAT L=<%02x> H=<%02x>, CTL L=<%02x> H=<%02x>", + stat_l, stat_h, mask_l, mask_h); + + if (!((stat_l & mask_l) || (stat_h & mask_h))) + return IRQ_NONE; + + if (stat_l) + SAA716x_EPWR(MSI, MSI_INT_STATUS_CLR_L, stat_l); + + if (stat_h) + SAA716x_EPWR(MSI, MSI_INT_STATUS_CLR_H, stat_h); + + saa716x_msi_event(saa716x, stat_l, stat_h); +#if 0 + dprintk(SAA716x_DEBUG, 1, "VI STAT 0=<%02x> 1=<%02x>, CTL 1=<%02x> 2=<%02x>", + SAA716x_EPRD(VI0, INT_STATUS), + SAA716x_EPRD(VI1, INT_STATUS), + SAA716x_EPRD(VI0, INT_ENABLE), + SAA716x_EPRD(VI1, INT_ENABLE)); + + dprintk(SAA716x_DEBUG, 1, "FGPI STAT 0=<%02x> 1=<%02x>, CTL 1=<%02x> 2=<%02x>", + SAA716x_EPRD(FGPI0, INT_STATUS), + SAA716x_EPRD(FGPI1, INT_STATUS), + SAA716x_EPRD(FGPI0, INT_ENABLE), + SAA716x_EPRD(FGPI0, INT_ENABLE)); + + dprintk(SAA716x_DEBUG, 1, "FGPI STAT 2=<%02x> 3=<%02x>, CTL 2=<%02x> 3=<%02x>", + SAA716x_EPRD(FGPI2, INT_STATUS), + SAA716x_EPRD(FGPI3, INT_STATUS), + SAA716x_EPRD(FGPI2, INT_ENABLE), + SAA716x_EPRD(FGPI3, INT_ENABLE)); + + dprintk(SAA716x_DEBUG, 1, "AI STAT 0=<%02x> 1=<%02x>, CTL 0=<%02x> 1=<%02x>", + SAA716x_EPRD(AI0, AI_STATUS), + SAA716x_EPRD(AI1, AI_STATUS), + SAA716x_EPRD(AI0, AI_CTL), + SAA716x_EPRD(AI1, AI_CTL)); + + dprintk(SAA716x_DEBUG, 1, "I2C STAT 0=<%02x> 1=<%02x>, CTL 0=<%02x> 1=<%02x>", + SAA716x_EPRD(I2C_A, INT_STATUS), + SAA716x_EPRD(I2C_B, INT_STATUS), + SAA716x_EPRD(I2C_A, INT_ENABLE), + SAA716x_EPRD(I2C_B, INT_ENABLE)); + + dprintk(SAA716x_DEBUG, 1, "DCS STAT=<%02x>, CTL=<%02x>", + SAA716x_EPRD(DCS, DCSC_INT_STATUS), + SAA716x_EPRD(DCS, DCSC_INT_ENABLE)); +#endif + + if (stat_l) { + if (stat_l & MSI_INT_TAGACK_FGPI_0) { + tasklet_schedule(&saa716x->fgpi[0].tasklet); + } + if (stat_l & MSI_INT_TAGACK_FGPI_1) { + tasklet_schedule(&saa716x->fgpi[1].tasklet); + } + if (stat_l & MSI_INT_TAGACK_FGPI_2) { + tasklet_schedule(&saa716x->fgpi[2].tasklet); + } + if (stat_l & MSI_INT_TAGACK_FGPI_3) { + tasklet_schedule(&saa716x->fgpi[3].tasklet); + } + } + + return IRQ_HANDLED; +} + +static void demux_worker(unsigned long data) +{ + struct saa716x_fgpi_stream_port *fgpi_entry = (struct saa716x_fgpi_stream_port *)data; + struct saa716x_dev *saa716x = fgpi_entry->saa716x; + struct dvb_demux *demux; + u32 fgpi_index; + u32 i; + u32 write_index; + + fgpi_index = fgpi_entry->dma_channel - 6; + demux = NULL; + for (i = 0; i < saa716x->config->adapters; i++) { + if (saa716x->config->adap_config[i].ts_port == fgpi_index) { + demux = &saa716x->saa716x_adap[i].demux; + break; + } + } + if (demux == NULL) { + printk(KERN_ERR "%s: unexpected channel %u\n", + __func__, fgpi_entry->dma_channel); + return; + } + + write_index = saa716x_fgpi_get_write_index(saa716x, fgpi_index); + if (write_index < 0) + return; + + dprintk(SAA716x_DEBUG, 1, "dma buffer = %d", write_index); + + if (write_index == fgpi_entry->read_index) { + printk(KERN_DEBUG "%s: called but nothing to do\n", __func__); + return; + } + + do { + u8 *data = (u8 *)fgpi_entry->dma_buf[fgpi_entry->read_index].mem_virt; + + pci_dma_sync_sg_for_cpu(saa716x->pdev, + fgpi_entry->dma_buf[fgpi_entry->read_index].sg_list, + fgpi_entry->dma_buf[fgpi_entry->read_index].list_len, + PCI_DMA_FROMDEVICE); + + dvb_dmx_swfilter(demux, data, 348 * 188); + + fgpi_entry->read_index = (fgpi_entry->read_index + 1) & 7; + } while (write_index != fgpi_entry->read_index); +} + +/* + * Twinhan/Azurewave VP-6090 + * DVB-S Frontend: 2x MB86A16 + * DVB-T Frontend: 2x TDA10046 + TDA8275 + */ +#define SAA716x_MODEL_TWINHAN_VP6090 "Twinhan/Azurewave VP-6090" +#define SAA716x_DEV_TWINHAN_VP6090 "2xDVB-S + 2xDVB-T + 2xAnalog" + +static int tda1004x_vp6090_request_firmware(struct dvb_frontend *fe, + const struct firmware **fw, + char *name) +{ + struct saa716x_adapter *adapter = fe->dvb->priv; + + return request_firmware(fw, name, &adapter->saa716x->pdev->dev); +} + +static struct tda1004x_config tda1004x_vp6090_config = { + .demod_address = 0x8, + .invert = 0, + .invert_oclk = 0, + .xtal_freq = TDA10046_XTAL_4M, + .agc_config = TDA10046_AGC_DEFAULT, + .if_freq = TDA10046_FREQ_3617, + .request_firmware = tda1004x_vp6090_request_firmware, +}; + +static int vp6090_dvbs_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +{ + struct saa716x_dev *saa716x = fe->dvb->priv; + + switch (voltage) { + case SEC_VOLTAGE_13: + dprintk(SAA716x_ERROR, 1, "Polarization=[13V]"); + break; + case SEC_VOLTAGE_18: + dprintk(SAA716x_ERROR, 1, "Polarization=[18V]"); + break; + case SEC_VOLTAGE_OFF: + dprintk(SAA716x_ERROR, 1, "Frontend (dummy) POWERDOWN"); + break; + default: + dprintk(SAA716x_ERROR, 1, "Invalid = (%d)", (u32 ) voltage); + return -EINVAL; + } + + return 0; +} + +struct mb86a16_config vp6090_mb86a16_config = { + .demod_address = 0x08, + .set_voltage = vp6090_dvbs_set_voltage, +}; + +static int saa716x_vp6090_frontend_attach(struct saa716x_adapter *adapter, int count) +{ + struct saa716x_dev *saa716x = adapter->saa716x; + struct saa716x_i2c *i2c = &saa716x->i2c[count]; + + dprintk(SAA716x_ERROR, 1, "Adapter (%d) SAA716x frontend Init", count); + dprintk(SAA716x_DEBUG, 1, "Adapter (%d) Device ID=%02x", count, saa716x->pdev->subsystem_device); + + dprintk(SAA716x_ERROR, 1, "Adapter (%d) Power ON", count); + + saa716x_gpio_set_output(saa716x, 11); + saa716x_gpio_set_output(saa716x, 10); + saa716x_gpio_write(saa716x, 11, 1); + saa716x_gpio_write(saa716x, 10, 1); + msleep(100); +#if 0 + dprintk(SAA716x_ERROR, 1, "Probing for MB86A16 (DVB-S/DSS)"); + adapter->fe = mb86a16_attach(&vp6090_mb86a16_config, &i2c->i2c_adapter); + if (adapter->fe) { + dprintk(SAA716x_ERROR, 1, "found MB86A16 DVB-S/DSS frontend @0x%02x", + vp6090_mb86a16_config.demod_address); + + } else { + goto exit; + } +#endif + adapter->fe = tda10046_attach(&tda1004x_vp6090_config, &i2c->i2c_adapter); + if (adapter->fe == NULL) { + dprintk(SAA716x_ERROR, 1, "Frontend attach failed"); + return -ENODEV; + } else { + dprintk(SAA716x_ERROR, 1, "Done!"); + return 0; + } + + return 0; +} + +static struct saa716x_config saa716x_vp6090_config = { + .model_name = SAA716x_MODEL_TWINHAN_VP6090, + .dev_type = SAA716x_DEV_TWINHAN_VP6090, + .boot_mode = SAA716x_EXT_BOOT, + .adapters = 1, + .frontend_attach = saa716x_vp6090_frontend_attach, + .irq_handler = saa716x_hybrid_pci_irq, + .i2c_rate = SAA716x_I2C_RATE_100, +}; + +/* + * NXP Reference design (Atlantis) + * 2x DVB-T Frontend: 2x TDA10046 + * Analog Decoder: 2x Internal + */ +#define SAA716x_MODEL_NXP_ATLANTIS "Atlantis reference board" +#define SAA716x_DEV_NXP_ATLANTIS "2x DVB-T + 2x Analog" + +static int tda1004x_atlantis_request_firmware(struct dvb_frontend *fe, + const struct firmware **fw, + char *name) +{ + struct saa716x_adapter *adapter = fe->dvb->priv; + + return request_firmware(fw, name, &adapter->saa716x->pdev->dev); +} + +static struct tda1004x_config tda1004x_atlantis_config = { + .demod_address = 0x8, + .invert = 0, + .invert_oclk = 0, + .xtal_freq = TDA10046_XTAL_16M, + .agc_config = TDA10046_AGC_TDA827X, + .if_freq = TDA10046_FREQ_045, + .request_firmware = tda1004x_atlantis_request_firmware, + .tuner_address = 0x60, +}; + +static struct tda827x_config tda827x_atlantis_config = { + .init = NULL, + .sleep = NULL, + .config = 0, + .switch_addr = 0, + .agcf = NULL, +}; + +static int saa716x_atlantis_frontend_attach(struct saa716x_adapter *adapter, + int count) +{ + struct saa716x_dev *saa716x = adapter->saa716x; + struct saa716x_i2c *i2c; + u8 i2c_buf[3] = { 0x05, 0x23, 0x01 }; /* activate the silent I2C bus */ + struct i2c_msg msg = { + .addr = 0x42 >> 1, + .flags = 0, + .buf = i2c_buf, + .len = sizeof(i2c_buf) + }; + + if (count < saa716x->config->adapters) { + u32 reset_gpio; + + dprintk(SAA716x_DEBUG, 1, "Adapter (%d) SAA716x frontend Init", + count); + dprintk(SAA716x_DEBUG, 1, "Adapter (%d) Device ID=%02x", count, + saa716x->pdev->subsystem_device); + + if (count == 0) { + reset_gpio = 14; + i2c = &saa716x->i2c[SAA716x_I2C_BUS_A]; + } else { + reset_gpio = 15; + i2c = &saa716x->i2c[SAA716x_I2C_BUS_B]; + } + + /* activate the silent I2C bus */ + i2c_transfer(&i2c->i2c_adapter, &msg, 1); + + saa716x_gpio_set_output(saa716x, reset_gpio); + + /* Reset the demodulator */ + saa716x_gpio_write(saa716x, reset_gpio, 1); + msleep(10); + saa716x_gpio_write(saa716x, reset_gpio, 0); + msleep(10); + saa716x_gpio_write(saa716x, reset_gpio, 1); + msleep(10); + + adapter->fe = tda10046_attach(&tda1004x_atlantis_config, + &i2c->i2c_adapter); + if (adapter->fe == NULL) + goto exit; + + dprintk(SAA716x_ERROR, 1, + "found TDA10046 DVB-T frontend @0x%02x", + tda1004x_atlantis_config.demod_address); + + if (dvb_attach(tda827x_attach, adapter->fe, + tda1004x_atlantis_config.tuner_address, + &i2c->i2c_adapter, &tda827x_atlantis_config)) { + dprintk(SAA716x_ERROR, 1, "found TDA8275 tuner @0x%02x", + tda1004x_atlantis_config.tuner_address); + } else { + goto exit; + } + + dprintk(SAA716x_ERROR, 1, "Done!"); + return 0; + } + +exit: + dprintk(SAA716x_ERROR, 1, "Frontend attach failed"); + return -ENODEV; +} + +static struct saa716x_config saa716x_atlantis_config = { + .model_name = SAA716x_MODEL_NXP_ATLANTIS, + .dev_type = SAA716x_DEV_NXP_ATLANTIS, + .boot_mode = SAA716x_EXT_BOOT, + .adapters = 2, + .frontend_attach = saa716x_atlantis_frontend_attach, + .irq_handler = saa716x_hybrid_pci_irq, + .i2c_rate = SAA716x_I2C_RATE_100, + .adap_config = { + { + /* Adapter 0 */ + .ts_port = 3, /* using FGPI 3 */ + .worker = demux_worker + }, + { + /* Adapter 1 */ + .ts_port = 0, /* using FGPI 0 */ + .worker = demux_worker + } + } +}; + +/* + * NXP Reference design (NEMO) + * DVB-T Frontend: 1x TDA10046 + TDA8275 + * Analog Decoder: External SAA7136 + */ +#define SAA716x_MODEL_NXP_NEMO "NEMO reference board" +#define SAA716x_DEV_NXP_NEMO "DVB-T + Analog" + +static int tda1004x_nemo_request_firmware(struct dvb_frontend *fe, + const struct firmware **fw, + char *name) +{ + struct saa716x_adapter *adapter = fe->dvb->priv; + + return request_firmware(fw, name, &adapter->saa716x->pdev->dev); +} + +static struct tda1004x_config tda1004x_nemo_config = { + .demod_address = 0x8, + .invert = 0, + .invert_oclk = 0, + .xtal_freq = TDA10046_XTAL_16M, + .agc_config = TDA10046_AGC_TDA827X, + .if_freq = TDA10046_FREQ_045, + .request_firmware = tda1004x_nemo_request_firmware, + .tuner_address = 0x60, +}; + +static struct tda827x_config tda827x_nemo_config = { + .init = NULL, + .sleep = NULL, + .config = 0, + .switch_addr = 0, + .agcf = NULL, +}; + +static int saa716x_nemo_frontend_attach(struct saa716x_adapter *adapter, int count) +{ + struct saa716x_dev *saa716x = adapter->saa716x; + struct saa716x_i2c *demod_i2c = &saa716x->i2c[SAA716x_I2C_BUS_B]; + struct saa716x_i2c *tuner_i2c = &saa716x->i2c[SAA716x_I2C_BUS_A]; + + + if (count == 0) { + dprintk(SAA716x_DEBUG, 1, "Adapter (%d) SAA716x frontend Init", count); + dprintk(SAA716x_DEBUG, 1, "Adapter (%d) Device ID=%02x", count, saa716x->pdev->subsystem_device); + dprintk(SAA716x_ERROR, 1, "Adapter (%d) Power ON", count); + + /* GPIO 26 controls a +15dB gain */ + saa716x_gpio_set_output(saa716x, 26); + saa716x_gpio_write(saa716x, 26, 0); + + saa716x_gpio_set_output(saa716x, 14); + + /* Reset the demodulator */ + saa716x_gpio_write(saa716x, 14, 1); + msleep(10); + saa716x_gpio_write(saa716x, 14, 0); + msleep(10); + saa716x_gpio_write(saa716x, 14, 1); + msleep(10); + + adapter->fe = tda10046_attach(&tda1004x_nemo_config, + &demod_i2c->i2c_adapter); + if (adapter->fe) { + dprintk(SAA716x_ERROR, 1, "found TDA10046 DVB-T frontend @0x%02x", + tda1004x_nemo_config.demod_address); + + } else { + goto exit; + } + if (dvb_attach(tda827x_attach, adapter->fe, + tda1004x_nemo_config.tuner_address, + &tuner_i2c->i2c_adapter, &tda827x_nemo_config)) { + dprintk(SAA716x_ERROR, 1, "found TDA8275 tuner @0x%02x", + tda1004x_nemo_config.tuner_address); + } else { + goto exit; + } + dprintk(SAA716x_ERROR, 1, "Done!"); + } + + return 0; +exit: + dprintk(SAA716x_ERROR, 1, "Frontend attach failed"); + return -ENODEV; +} + +static struct saa716x_config saa716x_nemo_config = { + .model_name = SAA716x_MODEL_NXP_NEMO, + .dev_type = SAA716x_DEV_NXP_NEMO, + .boot_mode = SAA716x_EXT_BOOT, + .adapters = 1, + .frontend_attach = saa716x_nemo_frontend_attach, + .irq_handler = saa716x_hybrid_pci_irq, + .i2c_rate = SAA716x_I2C_RATE_100, + + .adap_config = { + { + /* Adapter 0 */ + .ts_port = 3, /* using FGPI 3 */ + .worker = demux_worker + } + } +}; + + +#define SAA716x_MODEL_AVERMEDIA_HC82 "Avermedia HC82 Express-54" +#define SAA716x_DEV_AVERMEDIA_HC82 "DVB-T + Analog" + +#if 0 +static struct zl10353_config saa716x_averhc82_zl10353_config = { + .demod_address = 0x1f, + .adc_clock = 450560, + .if2 = 361667, + .no_tuner = 1, + .parallel_ts = 1, +}; +#endif + +static int saa716x_averhc82_frontend_attach(struct saa716x_adapter *adapter, int count) +{ + struct saa716x_dev *saa716x = adapter->saa716x; + + dprintk(SAA716x_DEBUG, 1, "Adapter (%d) SAA716x frontend Init", count); + dprintk(SAA716x_DEBUG, 1, "Adapter (%d) Device ID=%02x", count, saa716x->pdev->subsystem_device); + +// adapter->fe = zl10353_attach(&saa716x_averhc82_zl10353_config, &i2c->i2c_adapter); + + + return 0; +} + +static struct saa716x_config saa716x_averhc82_config = { + .model_name = SAA716x_MODEL_AVERMEDIA_HC82, + .dev_type = SAA716x_DEV_AVERMEDIA_HC82, + .boot_mode = SAA716x_EXT_BOOT, + .adapters = 1, + .frontend_attach = saa716x_averhc82_frontend_attach, + .irq_handler = saa716x_hybrid_pci_irq, + .i2c_rate = SAA716x_I2C_RATE_100, +}; + +#define SAA716x_MODEL_AVERMEDIA_H788 "Avermedia H788" +#define SAA716x_DEV_AVERMEDIA_H788 "DVB-T + Analaog" + +static int saa716x_averh88_frontend_attach(struct saa716x_adapter *adapter, int count) +{ + struct saa716x_dev *saa716x = adapter->saa716x; + + dprintk(SAA716x_DEBUG, 1, "Adapter (%d) SAA716x frontend Init", count); + dprintk(SAA716x_DEBUG, 1, "Adapter (%d) Device ID=%02x", count, saa716x->pdev->subsystem_device); + + return -ENODEV; +} + +static struct saa716x_config saa716x_averh788_config = { + .model_name = SAA716x_MODEL_AVERMEDIA_H788, + .dev_type = SAA716x_DEV_AVERMEDIA_H788, + .boot_mode = SAA716x_EXT_BOOT, + .adapters = 1, + .frontend_attach = saa716x_averh88_frontend_attach, + .irq_handler = saa716x_hybrid_pci_irq, + .i2c_rate = SAA716x_I2C_RATE_100, +}; + +static struct pci_device_id saa716x_hybrid_pci_table[] = { + + MAKE_ENTRY(TWINHAN_TECHNOLOGIES, TWINHAN_VP_6090, SAA7162, &saa716x_vp6090_config), + MAKE_ENTRY(AVERMEDIA, AVERMEDIA_HC82, SAA7160, &saa716x_averhc82_config), + MAKE_ENTRY(AVERMEDIA, AVERMEDIA_H788, SAA7160, &saa716x_averh788_config), + MAKE_ENTRY(KWORLD, KWORLD_DVB_T_PE310, SAA7162, &saa716x_atlantis_config), + MAKE_ENTRY(NXP_REFERENCE_BOARD, PCI_ANY_ID, SAA7162, &saa716x_atlantis_config), + MAKE_ENTRY(NXP_REFERENCE_BOARD, PCI_ANY_ID, SAA7160, &saa716x_nemo_config), + { } +}; +MODULE_DEVICE_TABLE(pci, saa716x_hybrid_pci_table); + +static struct pci_driver saa716x_hybrid_pci_driver = { + .name = DRIVER_NAME, + .id_table = saa716x_hybrid_pci_table, + .probe = saa716x_hybrid_pci_probe, + .remove = saa716x_hybrid_pci_remove, +}; + +static int saa716x_hybrid_init(void) +{ + return pci_register_driver(&saa716x_hybrid_pci_driver); +} + +static void saa716x_hybrid_exit(void) +{ + return pci_unregister_driver(&saa716x_hybrid_pci_driver); +} + +module_init(saa716x_hybrid_init); +module_exit(saa716x_hybrid_exit); + +MODULE_DESCRIPTION("SAA716x Hybrid driver"); +MODULE_AUTHOR("Manu Abraham"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/common/saa716x/saa716x_hybrid.h b/drivers/media/common/saa716x/saa716x_hybrid.h new file mode 100644 index 0000000..df34a59 --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_hybrid.h @@ -0,0 +1,13 @@ +#ifndef __SAA716x_HYBRID_H +#define __SAA716x_HYBRID_H + +#define TWINHAN_TECHNOLOGIES 0x1822 +#define AVERMEDIA 0x1461 +#define KWORLD 0x17DE + +#define TWINHAN_VP_6090 0x0027 +#define AVERMEDIA_HC82 0x2355 +#define AVERMEDIA_H788 0x1455 +#define KWORLD_DVB_T_PE310 0x7521 + +#endif /* __SAA716x_HYBRID_H */ diff --git a/drivers/media/common/saa716x/saa716x_i2c.c b/drivers/media/common/saa716x/saa716x_i2c.c new file mode 100644 index 0000000..91a091d --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_i2c.c @@ -0,0 +1,734 @@ +#include + +#include +#include +#include + +#include + +#include "saa716x_mod.h" + +#include "saa716x_i2c_reg.h" +#include "saa716x_msi_reg.h" +#include "saa716x_cgu_reg.h" + +#include "saa716x_i2c.h" +#include "saa716x_msi.h" +#include "saa716x_spi.h" +#include "saa716x_priv.h" + +#define SAA716x_I2C_TXFAIL (I2C_ERROR_IBE | \ + I2C_ACK_INTER_MTNA | \ + I2C_FAILURE_INTER_MAF) + +#define SAA716x_I2C_TXBUSY (I2C_TRANSMIT | \ + I2C_TRANSMIT_PROG) + +#define SAA716x_I2C_RXBUSY (I2C_RECEIVE | \ + I2C_RECEIVE_CLEAR) + +static const char* state[] = { + "Idle", + "DoneStop", + "Busy", + "TOscl", + "TOarb", + "DoneWrite", + "DoneRead", + "DoneWriteTO", + "DoneReadTO", + "NoDevice", + "NoACK", + "BUSErr", + "ArbLost", + "SEQErr", + "STErr" +}; + +int saa716x_i2c_irqevent(struct saa716x_dev *saa716x, u8 bus) +{ + u32 stat, mask; + u32 *I2C_DEV; + + BUG_ON(saa716x == NULL); + I2C_DEV = saa716x->I2C_DEV; + + stat = SAA716x_EPRD(I2C_DEV[bus], INT_STATUS); + mask = SAA716x_EPRD(I2C_DEV[bus], INT_ENABLE); + saa716x->i2c[bus].i2c_stat = stat; + dprintk(SAA716x_DEBUG, 0, "Bus(%d) I2C event: Status=<%s> --> Stat=<%02x> Mask=<%02x>", + bus, state[stat], stat, mask); + + if (!(stat & mask)) + return -1; + + SAA716x_EPWR(I2C_DEV[bus], INT_CLR_STATUS, stat); + + if (stat & I2C_INTERRUPT_STFNF) + dprintk(SAA716x_DEBUG, 0, " "); + + if (stat & I2C_INTERRUPT_MTFNF) { + dprintk(SAA716x_DEBUG, 0, " "); + } + + if (stat & I2C_INTERRUPT_RFDA) + dprintk(SAA716x_DEBUG, 0, " "); + + if (stat & I2C_INTERRUPTE_RFF) + dprintk(SAA716x_DEBUG, 0, " "); + + if (stat & I2C_SLAVE_INTERRUPT_STDR) + dprintk(SAA716x_DEBUG, 0, " "); + + if (stat & I2C_MASTER_INTERRUPT_MTDR) { + dprintk(SAA716x_DEBUG, 0, " "); + } + + if (stat & I2C_ERROR_IBE) + dprintk(SAA716x_DEBUG, 0, " "); + + if (stat & I2C_MODE_CHANGE_INTER_MSMC) + dprintk(SAA716x_DEBUG, 0, " "); + + if (stat & I2C_SLAVE_RECEIVE_INTER_SRSD) + dprintk(SAA716x_DEBUG, 0, " "); + + if (stat & I2C_SLAVE_TRANSMIT_INTER_STSD) + dprintk(SAA716x_DEBUG, 0, " "); + + if (stat & I2C_ACK_INTER_MTNA) + dprintk(SAA716x_DEBUG, 0, " "); + + if (stat & I2C_FAILURE_INTER_MAF) + dprintk(SAA716x_DEBUG, 0, " "); + + if (stat & I2C_INTERRUPT_MTD) + dprintk(SAA716x_DEBUG, 0, " "); + + return 0; +} + +static irqreturn_t saa716x_i2c_irq(int irq, void *dev_id) +{ + struct saa716x_dev *saa716x = (struct saa716x_dev *) dev_id; + + if (unlikely(saa716x == NULL)) { + printk("%s: saa716x=NULL", __func__); + return IRQ_NONE; + } + dprintk(SAA716x_DEBUG, 1, "MSI STAT L=<%02x> H=<%02x>, CTL L=<%02x> H=<%02x>", + SAA716x_EPRD(MSI, MSI_INT_STATUS_L), + SAA716x_EPRD(MSI, MSI_INT_STATUS_H), + SAA716x_EPRD(MSI, MSI_INT_ENA_L), + SAA716x_EPRD(MSI, MSI_INT_ENA_H)); + + dprintk(SAA716x_DEBUG, 1, "I2C STAT 0=<%02x> 1=<%02x>, CTL 0=<%02x> 1=<%02x>", + SAA716x_EPRD(I2C_A, INT_STATUS), + SAA716x_EPRD(I2C_B, INT_STATUS), + SAA716x_EPRD(I2C_A, INT_CLR_STATUS), + SAA716x_EPRD(I2C_B, INT_CLR_STATUS)); + + return IRQ_HANDLED; +} + +static void saa716x_term_xfer(struct saa716x_i2c *i2c, u32 I2C_DEV) +{ + struct saa716x_dev *saa716x = i2c->saa716x; + + SAA716x_EPWR(I2C_DEV, I2C_CONTROL, 0xc0); /* Start: SCL/SDA High */ + msleep(10); + SAA716x_EPWR(I2C_DEV, I2C_CONTROL, 0x80); + msleep(10); + SAA716x_EPWR(I2C_DEV, I2C_CONTROL, 0x00); + msleep(10); + SAA716x_EPWR(I2C_DEV, I2C_CONTROL, 0x80); + msleep(10); + SAA716x_EPWR(I2C_DEV, I2C_CONTROL, 0xc0); + + return; +} + +static void saa716x_i2c_hwdeinit(struct saa716x_i2c *i2c, u32 I2C_DEV) +{ + struct saa716x_dev *saa716x = i2c->saa716x; + + /* Disable all interrupts and clear status */ + SAA716x_EPWR(I2C_DEV, INT_CLR_ENABLE, 0x1fff); + SAA716x_EPWR(I2C_DEV, INT_CLR_STATUS, 0x1fff); +} + +static int saa716x_i2c_hwinit(struct saa716x_i2c *i2c, u32 I2C_DEV) +{ + struct saa716x_dev *saa716x = i2c->saa716x; + struct i2c_adapter *adapter = &i2c->i2c_adapter; + + int i, err = 0; + u32 reg; + + reg = SAA716x_EPRD(I2C_DEV, I2C_STATUS); + if (!(reg & 0xd)) { + dprintk(SAA716x_ERROR, 1, "Adapter (%02x) %s RESET failed, Exiting !", + I2C_DEV, adapter->name); + err = -EIO; + goto exit; + } + + /* Flush queue */ + SAA716x_EPWR(I2C_DEV, I2C_CONTROL, 0xcc); + + /* Disable all interrupts and clear status */ + SAA716x_EPWR(I2C_DEV, INT_CLR_ENABLE, 0x1fff); + SAA716x_EPWR(I2C_DEV, INT_CLR_STATUS, 0x1fff); + + /* Reset I2C Core and generate a delay */ + SAA716x_EPWR(I2C_DEV, I2C_CONTROL, 0xc1); + + for (i = 0; i < 100; i++) { + reg = SAA716x_EPRD(I2C_DEV, I2C_CONTROL); + if (reg == 0xc0) { + dprintk(SAA716x_ERROR, 1, "Adapter (%02x) %s RESET", + I2C_DEV, adapter->name); + break; + } + msleep(1); + + if (i == 99) + err = -EIO; + } + + if (err) { + dprintk(SAA716x_ERROR, 1, "Adapter (%02x) %s RESET failed", + I2C_DEV, adapter->name); + + saa716x_term_xfer(i2c, I2C_DEV); + err = -EIO; + goto exit; + } + + /* I2C Rate Setup */ + switch (i2c->i2c_rate) { + case SAA716x_I2C_RATE_400: + + dprintk(SAA716x_DEBUG, 1, "Initializing Adapter %s @ 400k", adapter->name); + SAA716x_EPWR(I2C_DEV, I2C_CLOCK_DIVISOR_HIGH, 0x1a); /* 0.5 * 27MHz/400kHz */ + SAA716x_EPWR(I2C_DEV, I2C_CLOCK_DIVISOR_LOW, 0x21); /* 0.5 * 27MHz/400kHz */ + SAA716x_EPWR(I2C_DEV, I2C_SDA_HOLD, 0x19); + break; + + case SAA716x_I2C_RATE_100: + + dprintk(SAA716x_DEBUG, 1, "Initializing Adapter %s @ 100k", adapter->name); + SAA716x_EPWR(I2C_DEV, I2C_CLOCK_DIVISOR_HIGH, 0x68); /* 0.5 * 27MHz/100kHz */ + SAA716x_EPWR(I2C_DEV, I2C_CLOCK_DIVISOR_LOW, 0x87); /* 0.5 * 27MHz/100kHz */ + SAA716x_EPWR(I2C_DEV, I2C_SDA_HOLD, 0x60); + break; + + default: + + dprintk(SAA716x_ERROR, 1, "Adapter %s Unknown Rate (Rate=0x%02x)", + adapter->name, + i2c->i2c_rate); + + break; + } + + /* Disable all interrupts and clear status */ + SAA716x_EPWR(I2C_DEV, INT_CLR_ENABLE, 0x1fff); + SAA716x_EPWR(I2C_DEV, INT_CLR_STATUS, 0x1fff); + + if (i2c->i2c_mode >= SAA716x_I2C_MODE_IRQ) { + /* Enabled interrupts: + * Master Transaction Done, + * Master Transaction Data Request + * (0x81) + */ + msleep(5); + + SAA716x_EPWR(I2C_DEV, INT_SET_ENABLE, + I2C_SET_ENABLE_MTDR | I2C_SET_ENABLE_MTD); + + /* Check interrupt enable status */ + reg = SAA716x_EPRD(I2C_DEV, INT_ENABLE); + if (reg != 0x81) { + + dprintk(SAA716x_ERROR, 1, + "Adapter (%d) %s Interrupt enable failed, Exiting !", + i, + adapter->name); + + err = -EIO; + goto exit; + } + } + + /* Check status */ + reg = SAA716x_EPRD(I2C_DEV, I2C_STATUS); + if (!(reg & 0xd)) { + + dprintk(SAA716x_ERROR, 1, + "Adapter (%02x) %s has bad state, Exiting !", + I2C_DEV, + adapter->name); + + err = -EIO; + goto exit; + } +#if 0 + saa716x_add_irqvector(saa716x, + i2c_vec[i].vector, + i2c_vec[i].edge, + i2c_vec[i].handler, + SAA716x_I2C_ADAPTER(i)); +#endif + reg = SAA716x_EPRD(CGU, CGU_SCR_3); + dprintk(SAA716x_DEBUG, 1, "Adapter (%02x) Autowake <%d> Active <%d>", + I2C_DEV, + (reg >> 1) & 0x01, + reg & 0x01); + + return 0; +exit: + return err; +} + +static int saa716x_i2c_send(struct saa716x_i2c *i2c, u32 I2C_DEV, u32 data) +{ + struct saa716x_dev *saa716x = i2c->saa716x; + int i, err = 0; + u32 reg; + + if (i2c->i2c_mode >= SAA716x_I2C_MODE_IRQ) { + /* Write to FIFO */ + SAA716x_EPWR(I2C_DEV, TX_FIFO, data); + return 0; + } + + /* Check FIFO status before TX */ + reg = SAA716x_EPRD(I2C_DEV, I2C_STATUS); + i2c->stat_tx_prior = reg; + if (reg & SAA716x_I2C_TXBUSY) { + for (i = 0; i < 100; i++) { + /* TODO! check for hotplug devices */ + msleep(10); + reg = SAA716x_EPRD(I2C_DEV, I2C_STATUS); + + if (reg & SAA716x_I2C_TXBUSY) { + dprintk(SAA716x_ERROR, 1, "FIFO full or Blocked"); + + err = saa716x_i2c_hwinit(i2c, I2C_DEV); + if (err < 0) { + dprintk(SAA716x_ERROR, 1, "Error Reinit"); + err = -EIO; + goto exit; + } + } else { + break; + } + } + } + + /* Write to FIFO */ + SAA716x_EPWR(I2C_DEV, TX_FIFO, data); + + /* Check for data write */ + for (i = 0; i < 1000; i++) { + /* TODO! check for hotplug devices */ + reg = SAA716x_EPRD(I2C_DEV, I2C_STATUS); + if (reg & I2C_TRANSMIT_CLEAR) { + break; + } + } + i2c->stat_tx_done = reg; + + if (!(reg & I2C_TRANSMIT_CLEAR)) { + dprintk(SAA716x_ERROR, 1, "TXFIFO not empty after Timeout, tried %d loops!", i); + err = -EIO; + goto exit; + } + + return err; + +exit: + dprintk(SAA716x_ERROR, 1, "I2C Send failed (Err=%d)", err); + return err; +} + +static int saa716x_i2c_recv(struct saa716x_i2c *i2c, u32 I2C_DEV, u32 *data) +{ + struct saa716x_dev *saa716x = i2c->saa716x; + int i, err = 0; + u32 reg; + + /* Check FIFO status before RX */ + for (i = 0; i < 1000; i++) { + reg = SAA716x_EPRD(I2C_DEV, I2C_STATUS); + if (!(reg & SAA716x_I2C_RXBUSY)) { + break; + } + } + if (reg & SAA716x_I2C_RXBUSY) { + dprintk(SAA716x_INFO, 1, "FIFO empty"); + err = -EIO; + goto exit; + } + + /* Read from FIFO */ + *data = SAA716x_EPRD(I2C_DEV, RX_FIFO); + + return 0; +exit: + dprintk(SAA716x_ERROR, 1, "Error Reading data, err=%d", err); + return err; +} + +static void saa716x_i2c_irq_start(struct saa716x_i2c *i2c, u32 I2C_DEV) +{ + struct saa716x_dev *saa716x = i2c->saa716x; + + if (i2c->i2c_mode == SAA716x_I2C_MODE_POLLING) + return; + + i2c->i2c_op = 1; + SAA716x_EPWR(I2C_DEV, INT_CLR_STATUS, 0x1fff); +} + +static int saa716x_i2c_irq_wait(struct saa716x_i2c *i2c, u32 I2C_DEV) +{ + struct saa716x_dev *saa716x = i2c->saa716x; + unsigned long timeout; + int err = 0; + + if (i2c->i2c_mode == SAA716x_I2C_MODE_POLLING) + return 0; + + timeout = HZ/100 + 1; /* 10ms */ + timeout = wait_event_interruptible_timeout(i2c->i2c_wq, i2c->i2c_op == 0, timeout); + if (timeout == -ERESTARTSYS || i2c->i2c_op) { + SAA716x_EPWR(I2C_DEV, INT_CLR_STATUS, 0x1fff); + if (timeout == -ERESTARTSYS) { + /* a signal arrived */ + err = -ERESTARTSYS; + } else { + dprintk(SAA716x_ERROR, 1, "timed out waiting for end of xfer!"); + err = -EIO; + } + } + return err; +} + +static int saa716x_i2c_write_msg(struct saa716x_i2c *i2c, u32 I2C_DEV, + u16 addr, u8 *buf, u16 len, u8 add_stop) +{ + struct saa716x_dev *saa716x = i2c->saa716x; + u32 data; + int err; + int i; + int bytes; + + saa716x_i2c_irq_start(i2c, I2C_DEV); + + /* first write START with I2C address */ + data = I2C_START_BIT | (addr << 1); + dprintk(SAA716x_DEBUG, 1, "length=%d Addr:0x%02x", len, data); + err = saa716x_i2c_send(i2c, I2C_DEV, data); + if (err < 0) { + dprintk(SAA716x_ERROR, 1, "Address write failed"); + goto exit; + } + + bytes = i2c->block_size - 1; + + /* now write the data */ + while (len > 0) { + if (bytes == i2c->block_size) { + /* this is not the first round, so restart irq */ + saa716x_i2c_irq_start(i2c, I2C_DEV); + } + + if (bytes > len) + bytes = len; + + for (i = 0; i < bytes; i++) { + data = buf[i]; + dprintk(SAA716x_DEBUG, 0, " 0x%02x\n", i, data); + if (add_stop && i == (len - 1)) + data |= I2C_STOP_BIT; + err = saa716x_i2c_send(i2c, I2C_DEV, data); + if (err < 0) { + dprintk(SAA716x_ERROR, 1, "Data send failed"); + goto exit; + } + } + + err = saa716x_i2c_irq_wait(i2c, I2C_DEV); + if (err < 0) { + goto exit; + } + + len -= bytes; + buf += bytes; + bytes = i2c->block_size; + } + + return 0; + +exit: + dprintk(SAA716x_ERROR, 1, "Error writing data, err=%d", err); + return err; +} + +static int saa716x_i2c_read_msg(struct saa716x_i2c *i2c, u32 I2C_DEV, + u16 addr, u8 *buf, u16 len, u8 add_stop) +{ + struct saa716x_dev *saa716x = i2c->saa716x; + u32 data; + int err; + int i; + int bytes; + + saa716x_i2c_irq_start(i2c, I2C_DEV); + + /* first write START with I2C address */ + data = I2C_START_BIT | (addr << 1) | 1; + dprintk(SAA716x_DEBUG, 1, "length=%d Addr:0x%02x", len, data); + err = saa716x_i2c_send(i2c, I2C_DEV, data); + if (err < 0) { + dprintk(SAA716x_ERROR, 1, "Address write failed"); + goto exit; + } + + bytes = i2c->block_size - 1; + + /* now read the data */ + while (len > 0) { + if (bytes == i2c->block_size) { + /* this is not the first round, so restart irq */ + saa716x_i2c_irq_start(i2c, I2C_DEV); + } + + if (bytes > len) + bytes = len; + + for (i = 0; i < bytes; i++) { + data = 0x00; /* dummy write for reading */ + if (add_stop && i == (len - 1)) + data |= I2C_STOP_BIT; + err = saa716x_i2c_send(i2c, I2C_DEV, data); + if (err < 0) { + dprintk(SAA716x_ERROR, 1, "Data send failed"); + goto exit; + } + } + + err = saa716x_i2c_irq_wait(i2c, I2C_DEV); + if (err < 0) { + goto exit; + } + + for (i = 0; i < bytes; i++) { + err = saa716x_i2c_recv(i2c, I2C_DEV, &data); + if (err < 0) { + dprintk(SAA716x_ERROR, 1, "Data receive failed"); + goto exit; + } + dprintk(SAA716x_DEBUG, 0, " 0x%02x\n\n", i, data); + buf[i] = data; + } + + len -= bytes; + buf += bytes; + bytes = i2c->block_size; + } + + return 0; + +exit: + dprintk(SAA716x_ERROR, 1, "Error reading data, err=%d", err); + return err; +} + +static int saa716x_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) +{ + struct saa716x_i2c *i2c = i2c_get_adapdata(adapter); + struct saa716x_dev *saa716x = i2c->saa716x; + + u32 DEV = SAA716x_I2C_BUS(i2c->i2c_dev); + int i, j, err = 0; + int t; + + dprintk(SAA716x_DEBUG, 0, "\n"); + dprintk(SAA716x_DEBUG, 1, "Bus(%02x) I2C transfer", DEV); + mutex_lock(&i2c->i2c_lock); + + for (t = 0; t < 3; t++) { + for (i = 0; i < num; i++) { + if (msgs[i].flags & I2C_M_RD) + err = saa716x_i2c_read_msg(i2c, DEV, + msgs[i].addr, msgs[i].buf, msgs[i].len, + i == (num - 1)); + else + err = saa716x_i2c_write_msg(i2c, DEV, + msgs[i].addr, msgs[i].buf, msgs[i].len, + i == (num - 1)); + if (err < 0) { + err = -EIO; + goto retry; + } + } + break; +retry: + dprintk(SAA716x_INFO, 1, "Error in Transfer, try %d", t); + for (i = 0; i < num; i++) { + dprintk(SAA716x_INFO, 1, "msg %d, addr = 0x%02x, len=%d, flags=0x%x", + i, msgs[i].addr, msgs[i].len, msgs[i].flags); + if (!(msgs[i].flags & I2C_M_RD)) { + for (j = 0; j < msgs[i].len; j++) { + dprintk(SAA716x_INFO, 1, " 0x%02x", + j, msgs[i].buf[j]); + } + } + } + err = saa716x_i2c_hwinit(i2c, DEV); + if (err < 0) { + dprintk(SAA716x_ERROR, 1, "Error Reinit"); + err = -EIO; + goto bail_out; + } + } + + mutex_unlock(&i2c->i2c_lock); + return num; + +bail_out: + dprintk(SAA716x_ERROR, 1, "ERROR: Bailing out <%d>", err); + mutex_unlock(&i2c->i2c_lock); + return err; +} + +static u32 saa716x_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm saa716x_algo = { + .master_xfer = saa716x_i2c_xfer, + .functionality = saa716x_i2c_func, +}; + +struct saa716x_i2cvec { + u32 vector; + enum saa716x_edge edge; + irqreturn_t (*handler)(int irq, void *dev_id); +}; + +static const struct saa716x_i2cvec i2c_vec[] = { + { + .vector = I2CINT_0, + .edge = SAA716x_EDGE_RISING, + .handler = saa716x_i2c_irq + }, { + .vector = I2CINT_1, + .edge = SAA716x_EDGE_RISING, + .handler = saa716x_i2c_irq + } +}; + +int saa716x_i2c_init(struct saa716x_dev *saa716x) +{ + struct pci_dev *pdev = saa716x->pdev; + struct saa716x_i2c *i2c = saa716x->i2c; + struct i2c_adapter *adapter = NULL; + + int i, err = 0; + + dprintk(SAA716x_DEBUG, 1, "Initializing SAA%02x I2C Core", + saa716x->pdev->device); + + for (i = 0; i < SAA716x_I2C_ADAPTERS; i++) { + + mutex_init(&i2c->i2c_lock); + + init_waitqueue_head(&i2c->i2c_wq); + i2c->i2c_op = 0; + + i2c->i2c_dev = i; + i2c->i2c_rate = saa716x->config->i2c_rate; + i2c->i2c_mode = saa716x->config->i2c_mode; + adapter = &i2c->i2c_adapter; + + if (i2c->i2c_mode == SAA716x_I2C_MODE_IRQ_BUFFERED) + i2c->block_size = 8; + else + i2c->block_size = 1; + + if (adapter != NULL) { + + i2c_set_adapdata(adapter, i2c); + + strcpy(adapter->name, SAA716x_I2C_ADAPTER(i)); + + adapter->owner = THIS_MODULE; + adapter->algo = &saa716x_algo; + adapter->algo_data = NULL; + adapter->timeout = 500; /* FIXME ! */ + adapter->retries = 3; /* FIXME ! */ + adapter->dev.parent = &pdev->dev; + + dprintk(SAA716x_DEBUG, 1, "Initializing adapter (%d) %s", + i, + adapter->name); + + err = i2c_add_adapter(adapter); + if (err < 0) { + dprintk(SAA716x_ERROR, 1, "Adapter (%d) %s init failed", i, adapter->name); + goto exit; + } + + i2c->saa716x = saa716x; + saa716x_i2c_hwinit(i2c, SAA716x_I2C_BUS(i)); + } + i2c++; + } + + if (saa716x->config->i2c_mode >= SAA716x_I2C_MODE_IRQ) { + SAA716x_EPWR(MSI, MSI_INT_ENA_SET_H, MSI_INT_I2CINT_0); + SAA716x_EPWR(MSI, MSI_INT_ENA_SET_H, MSI_INT_I2CINT_1); + } + + dprintk(SAA716x_DEBUG, 1, "SAA%02x I2C Core succesfully initialized", + saa716x->pdev->device); + + return 0; +exit: + return err; +} +EXPORT_SYMBOL_GPL(saa716x_i2c_init); + +int saa716x_i2c_exit(struct saa716x_dev *saa716x) +{ + struct saa716x_i2c *i2c = saa716x->i2c; + struct i2c_adapter *adapter = NULL; + int i, err = 0; + + dprintk(SAA716x_DEBUG, 1, "Removing SAA%02x I2C Core", saa716x->pdev->device); + + for (i = 0; i < SAA716x_I2C_ADAPTERS; i++) { + + adapter = &i2c->i2c_adapter; +#if 0 + saa716x_remove_irqvector(saa716x, i2c_vec[i].vector); +#endif + saa716x_i2c_hwdeinit(i2c, SAA716x_I2C_BUS(i)); + dprintk(SAA716x_DEBUG, 1, "Removing adapter (%d) %s", i, adapter->name); + + i2c_del_adapter(adapter); + i2c++; + } + dprintk(SAA716x_DEBUG, 1, "SAA%02x I2C Core succesfully removed", saa716x->pdev->device); + + return 0; + +exit: + return err; +} +EXPORT_SYMBOL_GPL(saa716x_i2c_exit); diff --git a/drivers/media/common/saa716x/saa716x_i2c.h b/drivers/media/common/saa716x/saa716x_i2c.h new file mode 100644 index 0000000..da767ac --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_i2c.h @@ -0,0 +1,52 @@ +#ifndef __SAA716x_I2C_H +#define __SAA716x_I2C_H + +#define SAA716x_I2C_ADAPTERS 2 + +#define SAA716x_I2C_ADAPTER(__dev) (( \ + (__dev == 1) ? \ + "SAA716x I2C Core 1" : \ + "SAA716x I2C Core 0")) + +#define SAA716x_I2C_BUS(__x) ((__x == 1) ? 0x0000c000 : 0x0000b000) + +#define SAA716x_I2C_BUS_A 0x01 +#define SAA716x_I2C_BUS_B 0x00 + +struct saa716x_dev; + +enum saa716x_i2c_rate { + SAA716x_I2C_RATE_400 = 1, + SAA716x_I2C_RATE_100, +}; + +enum saa716x_i2c_mode { + SAA716x_I2C_MODE_POLLING = 0, + SAA716x_I2C_MODE_IRQ, + SAA716x_I2C_MODE_IRQ_BUFFERED +}; + +struct saa716x_i2c { + struct i2c_adapter i2c_adapter; + struct mutex i2c_lock; + struct saa716x_dev *saa716x; + u8 i2c_dev; + + enum saa716x_i2c_rate i2c_rate; /* run time */ + enum saa716x_i2c_mode i2c_mode; + u32 block_size; /* block size for buffered + mode, 1 otherwise */ + u32 i2c_stat; + + u32 stat_tx_prior; + u32 stat_tx_done; + wait_queue_head_t i2c_wq; + int i2c_op; +}; + +extern int saa716x_i2c_init(struct saa716x_dev *saa716x); +extern int saa716x_i2c_exit(struct saa716x_dev *saa716x); +extern void saa716x_i2cint_disable(struct saa716x_dev *saa716x); +extern int saa716x_i2c_irqevent(struct saa716x_dev *saa716x, u8 bus); + +#endif /* __SAA716x_I2C_H */ diff --git a/drivers/media/common/saa716x/saa716x_i2c_reg.h b/drivers/media/common/saa716x/saa716x_i2c_reg.h new file mode 100644 index 0000000..8fa992c --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_i2c_reg.h @@ -0,0 +1,145 @@ +#ifndef __SAA716x_I2C_REG_H +#define __SAA716x_I2C_REG_H + +/* -------------- I2C Registers -------------- */ + +#define RX_FIFO 0x000 +#define I2C_RX_BYTE (0x000000ff << 0) + +#define TX_FIFO 0x000 +#define I2C_STOP_BIT (0x00000001 << 9) +#define I2C_START_BIT (0x00000001 << 8) +#define I2C_TX_BYTE (0x000000ff << 0) + +#define I2C_STATUS 0x008 +#define I2C_TRANSMIT (0x00000001 << 11) +#define I2C_RECEIVE (0x00000001 << 10) +#define I2C_TRANSMIT_S_PROG (0x00000001 << 9) +#define I2C_TRANSMIT_S_CLEAR (0x00000001 << 8) +#define I2C_TRANSMIT_PROG (0x00000001 << 7) +#define I2C_TRANSMIT_CLEAR (0x00000001 << 6) +#define I2C_RECEIVE_PROG (0x00000001 << 5) +#define I2C_RECEIVE_CLEAR (0x00000001 << 4) +#define I2C_SDA_LINE (0x00000001 << 3) +#define I2C_SCL_LINE (0x00000001 << 2) +#define I2C_START_STOP_FLAG (0x00000001 << 1) +#define I2C_MODE_STATUS (0x00000001 << 0) + +#define I2C_CONTROL 0x00c +#define I2C_SCL_CONTROL (0x00000001 << 7) +#define I2C_SDA_CONTROL (0x00000001 << 6) +#define I2C_RECEIVE_PROTECT (0x00000001 << 5) +#define I2C_RECEIVE_PRO_READ (0x00000001 << 4) +#define I2C_TRANS_SELF_CLEAR (0x00000001 << 3) +#define I2C_TRANS_S_SELF_CLEAR (0x00000001 << 2) +#define I2C_SLAVE_ADDR_10BIT (0x00000001 << 1) +#define I2C_RESET (0x00000001 << 0) + +#define I2C_CLOCK_DIVISOR_HIGH 0x010 +#define I2C_CLOCK_HIGH (0x0000ffff << 0) + +#define I2C_CLOCK_DIVISOR_LOW 0x014 +#define I2C_CLOCK_LOW (0x0000ffff << 0) + +#define I2C_RX_LEVEL 0x01c +#define I2C_RECEIVE_RANGE (0x0000007f << 0) + +#define I2C_TX_LEVEL 0x020 +#define I2C_TRANSMIT_RANGE (0x0000007f << 0) + +#define I2C_SDA_HOLD 0x028 +#define I2C_HOLD_TIME (0x0000007f << 0) + +#define MODULE_CONF 0xfd4 +#define INT_CLR_ENABLE 0xfd8 +#define I2C_CLR_ENABLE_STFNF (0x00000001 << 12) +#define I2C_CLR_ENABLE_MTFNF (0x00000001 << 11) +#define I2C_CLR_ENABLE_RFDA (0x00000001 << 10) +#define I2C_CLR_ENABLE_RFF (0x00000001 << 9) +#define I2C_CLR_ENABLE_STDR (0x00000001 << 8) +#define I2C_CLR_ENABLE_MTDR (0x00000001 << 7) +#define I2C_CLR_ENABLE_IBE (0x00000001 << 6) +#define I2C_CLR_ENABLE_MSMC (0x00000001 << 5) +#define I2C_CLR_ENABLE_SRSD (0x00000001 << 4) +#define I2C_CLR_ENABLE_STSD (0x00000001 << 3) +#define I2C_CLR_ENABLE_MTNA (0x00000001 << 2) +#define I2C_CLR_ENABLE_MAF (0x00000001 << 1) +#define I2C_CLR_ENABLE_MTD (0x00000001 << 0) + +#define INT_SET_ENABLE 0xfdc +#define I2C_SET_ENABLE_STFNF (0x00000001 << 12) +#define I2C_SET_ENABLE_MTFNF (0x00000001 << 11) +#define I2C_SET_ENABLE_RFDA (0x00000001 << 10) +#define I2C_SET_ENABLE_RFF (0x00000001 << 9) +#define I2C_SET_ENABLE_STDR (0x00000001 << 8) +#define I2C_SET_ENABLE_MTDR (0x00000001 << 7) +#define I2C_SET_ENABLE_IBE (0x00000001 << 6) +#define I2C_SET_ENABLE_MSMC (0x00000001 << 5) +#define I2C_SET_ENABLE_SRSD (0x00000001 << 4) +#define I2C_SET_ENABLE_STSD (0x00000001 << 3) +#define I2C_SET_ENABLE_MTNA (0x00000001 << 2) +#define I2C_SET_ENABLE_MAF (0x00000001 << 1) +#define I2C_SET_ENABLE_MTD (0x00000001 << 0) + +#define INT_STATUS 0xfe0 +#define I2C_INTERRUPT_STFNF (0x00000001 << 12) +#define I2C_INTERRUPT_MTFNF (0x00000001 << 11) +#define I2C_INTERRUPT_RFDA (0x00000001 << 10) +#define I2C_INTERRUPTE_RFF (0x00000001 << 9) +#define I2C_SLAVE_INTERRUPT_STDR (0x00000001 << 8) +#define I2C_MASTER_INTERRUPT_MTDR (0x00000001 << 7) +#define I2C_ERROR_IBE (0x00000001 << 6) +#define I2C_MODE_CHANGE_INTER_MSMC (0x00000001 << 5) +#define I2C_SLAVE_RECEIVE_INTER_SRSD (0x00000001 << 4) +#define I2C_SLAVE_TRANSMIT_INTER_STSD (0x00000001 << 3) +#define I2C_ACK_INTER_MTNA (0x00000001 << 2) +#define I2C_FAILURE_INTER_MAF (0x00000001 << 1) +#define I2C_INTERRUPT_MTD (0x00000001 << 0) + +#define INT_ENABLE 0xfe4 +#define I2C_ENABLE_STFNF (0x00000001 << 12) +#define I2C_ENABLE_MTFNF (0x00000001 << 11) +#define I2C_ENABLE_RFDA (0x00000001 << 10) +#define I2C_ENABLE_RFF (0x00000001 << 9) +#define I2C_ENABLE_STDR (0x00000001 << 8) +#define I2C_ENABLE_MTDR (0x00000001 << 7) +#define I2C_ENABLE_IBE (0x00000001 << 6) +#define I2C_ENABLE_MSMC (0x00000001 << 5) +#define I2C_ENABLE_SRSD (0x00000001 << 4) +#define I2C_ENABLE_STSD (0x00000001 << 3) +#define I2C_ENABLE_MTNA (0x00000001 << 2) +#define I2C_ENABLE_MAF (0x00000001 << 1) +#define I2C_ENABLE_MTD (0x00000001 << 0) + +#define INT_CLR_STATUS 0xfe8 +#define I2C_CLR_STATUS_STFNF (0x00000001 << 12) +#define I2C_CLR_STATUS_MTFNF (0x00000001 << 11) +#define I2C_CLR_STATUS_RFDA (0x00000001 << 10) +#define I2C_CLR_STATUS_RFF (0x00000001 << 9) +#define I2C_CLR_STATUS_STDR (0x00000001 << 8) +#define I2C_CLR_STATUS_MTDR (0x00000001 << 7) +#define I2C_CLR_STATUS_IBE (0x00000001 << 6) +#define I2C_CLR_STATUS_MSMC (0x00000001 << 5) +#define I2C_CLR_STATUS_SRSD (0x00000001 << 4) +#define I2C_CLR_STATUS_STSD (0x00000001 << 3) +#define I2C_CLR_STATUS_MTNA (0x00000001 << 2) +#define I2C_CLR_STATUS_MAF (0x00000001 << 1) +#define I2C_CLR_STATIS_MTD (0x00000001 << 0) + +#define INT_SET_STATUS 0xfec +#define I2C_SET_STATUS_STFNF (0x00000001 << 12) +#define I2C_SET_STATUS_MTFNF (0x00000001 << 11) +#define I2C_SET_STATUS_RFDA (0x00000001 << 10) +#define I2C_SET_STATUS_RFF (0x00000001 << 9) +#define I2C_SET_STATUS_STDR (0x00000001 << 8) +#define I2C_SET_STATUS_MTDR (0x00000001 << 7) +#define I2C_SET_STATUS_IBE (0x00000001 << 6) +#define I2C_SET_STATUS_MSMC (0x00000001 << 5) +#define I2C_SET_STATUS_SRSD (0x00000001 << 4) +#define I2C_SET_STATUS_STSD (0x00000001 << 3) +#define I2C_SET_STATUS_MTNA (0x00000001 << 2) +#define I2C_SET_STATUS_MAF (0x00000001 << 1) +#define I2C_SET_STATIS_MTD (0x00000001 << 0) + + +#endif /* __SAA716x_I2C_REG_H */ diff --git a/drivers/media/common/saa716x/saa716x_mod.h b/drivers/media/common/saa716x/saa716x_mod.h new file mode 100644 index 0000000..273efdd --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_mod.h @@ -0,0 +1,50 @@ +#ifndef __SAA716x_MOD_H +#define __SAA716x_MOD_H + +/* BAR = 17 bits */ +/* + VI0 0x00000000 + VI1 0x00001000 + FGPI0 0x00002000 + FGPI1 0x00003000 + FGPI2 0x00004000 + FGPI3 0x00005000 + AI0 0x00006000 + AI1 0x00007000 + BAM 0x00008000 + MMU 0x00009000 + MSI 0x0000a000 + I2C_B 0x0000b000 + I2C_A 0x0000c000 + SPI 0x0000d000 + GPIO 0x0000e000 + PHI_0 0x0000f000 + CGU 0x00013000 + DCS 0x00014000 + GREG 0x00012000 + + PHI_1 0x00020000 +*/ + +#define VI0 0x00000000 +#define VI1 0x00001000 +#define FGPI0 0x00002000 +#define FGPI1 0x00003000 +#define FGPI2 0x00004000 +#define FGPI3 0x00005000 +#define AI0 0x00006000 +#define AI1 0x00007000 +#define BAM 0x00008000 +#define MMU 0x00009000 +#define MSI 0x0000a000 +#define I2C_B 0x0000b000 +#define I2C_A 0x0000c000 +#define SPI 0x0000d000 +#define GPIO 0x0000e000 +#define PHI_0 0x0000f000 +#define GREG 0x00012000 +#define CGU 0x00013000 +#define DCS 0x00014000 +#define PHI_1 0x00020000 + +#endif /* __SAA716x_MOD_H */ diff --git a/drivers/media/common/saa716x/saa716x_msi.c b/drivers/media/common/saa716x/saa716x_msi.c new file mode 100644 index 0000000..b0f05a2 --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_msi.c @@ -0,0 +1,479 @@ +#include + +#include +#include +#include + +#include "saa716x_mod.h" + +#include "saa716x_msi_reg.h" +#include "saa716x_msi.h" +#include "saa716x_spi.h" + +#include "saa716x_priv.h" + +#define SAA716x_MSI_VECTORS 50 + +static const char *vector_name[] = { + "TAGACK_VI0_0", + "TAGACK_VI0_1", + "TAGACK_VI0_2", + "TAGACK_VI1_0", + "TAGACK_VI1_1", + "TAGACK_VI1_2", + "TAGACK_FGPI_0", + "TAGACK_FGPI_1", + "TAGACK_FGPI_2", + "TAGACK_FGPI_3", + "TAGACK_AI_0", + "TAGACK_AI_1", + "OVRFLW_VI0_0", + "OVRFLW_VI0_1", + "OVRFLW_VI0_2", + "OVRFLW_VI1_0", + "OVRFLW_VI1_1", + "OVRFLW_VI1_2", + "OVRFLW_FGPI_O", + "OVRFLW_FGPI_1", + "OVRFLW_FGPI_2", + "OVRFLW_FGPI_3", + "OVRFLW_AI_0", + "OVRFLW_AI_1", + "AVINT_VI0", + "AVINT_VI1", + "AVINT_FGPI_0", + "AVINT_FGPI_1", + "AVINT_FGPI_2", + "AVINT_FGPI_3", + "AVINT_AI_0", + "AVINT_AI_1", + "UNMAPD_TC_INT", + "EXTINT_0", + "EXTINT_1", + "EXTINT_2", + "EXTINT_3", + "EXTINT_4", + "EXTINT_5", + "EXTINT_6", + "EXTINT_7", + "EXTINT_8", + "EXTINT_9", + "EXTINT_10", + "EXTINT_11", + "EXTINT_12", + "EXTINT_13", + "EXTINT_14", + "EXTINT_15", + "I2CINT_0", + "I2CINT_1" +}; + +static u32 MSI_CONFIG_REG[51] = { + MSI_CONFIG0, + MSI_CONFIG1, + MSI_CONFIG2, + MSI_CONFIG3, + MSI_CONFIG4, + MSI_CONFIG5, + MSI_CONFIG6, + MSI_CONFIG7, + MSI_CONFIG8, + MSI_CONFIG9, + MSI_CONFIG10, + MSI_CONFIG11, + MSI_CONFIG12, + MSI_CONFIG13, + MSI_CONFIG14, + MSI_CONFIG15, + MSI_CONFIG16, + MSI_CONFIG17, + MSI_CONFIG18, + MSI_CONFIG19, + MSI_CONFIG20, + MSI_CONFIG21, + MSI_CONFIG22, + MSI_CONFIG23, + MSI_CONFIG24, + MSI_CONFIG25, + MSI_CONFIG26, + MSI_CONFIG27, + MSI_CONFIG28, + MSI_CONFIG29, + MSI_CONFIG30, + MSI_CONFIG31, + MSI_CONFIG32, + MSI_CONFIG33, + MSI_CONFIG34, + MSI_CONFIG35, + MSI_CONFIG36, + MSI_CONFIG37, + MSI_CONFIG38, + MSI_CONFIG39, + MSI_CONFIG40, + MSI_CONFIG41, + MSI_CONFIG42, + MSI_CONFIG43, + MSI_CONFIG44, + MSI_CONFIG45, + MSI_CONFIG46, + MSI_CONFIG47, + MSI_CONFIG48, + MSI_CONFIG49, + MSI_CONFIG50 +}; + +int saa716x_msi_event(struct saa716x_dev *saa716x, u32 stat_l, u32 stat_h) +{ + dprintk(SAA716x_DEBUG, 0, "%s: MSI event ", __func__); + + if (stat_l & MSI_INT_TAGACK_VI0_0) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[0]); + + if (stat_l & MSI_INT_TAGACK_VI0_1) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[1]); + + if (stat_l & MSI_INT_TAGACK_VI0_2) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[2]); + + if (stat_l & MSI_INT_TAGACK_VI1_0) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[3]); + + if (stat_l & MSI_INT_TAGACK_VI1_1) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[4]); + + if (stat_l & MSI_INT_TAGACK_VI1_2) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[5]); + + if (stat_l & MSI_INT_TAGACK_FGPI_0) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[6]); + + if (stat_l & MSI_INT_TAGACK_FGPI_1) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[7]); + + if (stat_l & MSI_INT_TAGACK_FGPI_2) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[8]); + + if (stat_l & MSI_INT_TAGACK_FGPI_3) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[9]); + + if (stat_l & MSI_INT_TAGACK_AI_0) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[10]); + + if (stat_l & MSI_INT_TAGACK_AI_1) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[11]); + + if (stat_l & MSI_INT_OVRFLW_VI0_0) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[12]); + + if (stat_l & MSI_INT_OVRFLW_VI0_1) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[13]); + + if (stat_l & MSI_INT_OVRFLW_VI0_2) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[14]); + + if (stat_l & MSI_INT_OVRFLW_VI1_0) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[15]); + + if (stat_l & MSI_INT_OVRFLW_VI1_1) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[16]); + + if (stat_l & MSI_INT_OVRFLW_VI1_2) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[17]); + + if (stat_l & MSI_INT_OVRFLW_FGPI_0) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[18]); + + if (stat_l & MSI_INT_OVRFLW_FGPI_1) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[19]); + + if (stat_l & MSI_INT_OVRFLW_FGPI_2) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[20]); + + if (stat_l & MSI_INT_OVRFLW_FGPI_3) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[21]); + + if (stat_l & MSI_INT_OVRFLW_AI_0) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[22]); + + if (stat_l & MSI_INT_OVRFLW_AI_1) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[23]); + + if (stat_l & MSI_INT_AVINT_VI0) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[24]); + + if (stat_l & MSI_INT_AVINT_VI1) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[25]); + + if (stat_l & MSI_INT_AVINT_FGPI_0) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[26]); + + if (stat_l & MSI_INT_AVINT_FGPI_1) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[27]); + + if (stat_l & MSI_INT_AVINT_FGPI_2) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[28]); + + if (stat_l & MSI_INT_AVINT_FGPI_3) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[29]); + + if (stat_l & MSI_INT_AVINT_AI_0) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[30]); + + if (stat_l & MSI_INT_AVINT_AI_1) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[31]); + + if (stat_h & MSI_INT_UNMAPD_TC_INT) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[32]); + + if (stat_h & MSI_INT_EXTINT_0) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[33]); + + if (stat_h & MSI_INT_EXTINT_1) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[34]); + + if (stat_h & MSI_INT_EXTINT_2) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[35]); + + if (stat_h & MSI_INT_EXTINT_3) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[36]); + + if (stat_h & MSI_INT_EXTINT_4) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[37]); + + if (stat_h & MSI_INT_EXTINT_5) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[38]); + + if (stat_h & MSI_INT_EXTINT_6) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[39]); + + if (stat_h & MSI_INT_EXTINT_7) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[40]); + + if (stat_h & MSI_INT_EXTINT_8) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[41]); + + if (stat_h & MSI_INT_EXTINT_9) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[42]); + + if (stat_h & MSI_INT_EXTINT_10) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[43]); + + if (stat_h & MSI_INT_EXTINT_11) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[44]); + + if (stat_h & MSI_INT_EXTINT_12) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[45]); + + if (stat_h & MSI_INT_EXTINT_13) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[46]); + + if (stat_h & MSI_INT_EXTINT_14) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[47]); + + if (stat_h & MSI_INT_EXTINT_15) + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[48]); + + if (stat_h & MSI_INT_I2CINT_0) { + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[49]); + saa716x_i2c_irqevent(saa716x, 0); + } + + if (stat_h & MSI_INT_I2CINT_1) { + dprintk(SAA716x_DEBUG, 0, "<%s> ", vector_name[50]); + saa716x_i2c_irqevent(saa716x, 1); + } + + dprintk(SAA716x_DEBUG, 0, "\n"); + + return 0; +} +EXPORT_SYMBOL_GPL(saa716x_msi_event); + +int saa716x_msi_init(struct saa716x_dev *saa716x) +{ + u32 ena_l, ena_h, sta_l, sta_h, mid; + int i; + + dprintk(SAA716x_DEBUG, 1, "Initializing MSI .."); + saa716x->handlers = 0; + + /* get module id & version */ + mid = SAA716x_EPRD(MSI, MSI_MODULE_ID); + if (mid != 0x30100) + dprintk(SAA716x_ERROR, 1, "MSI Id<%04x> is not supported", mid); + + /* let HW take care of MSI race */ + SAA716x_EPWR(MSI, MSI_DELAY_TIMER, 0x0); + + /* INTA Polarity: Active High */ + SAA716x_EPWR(MSI, MSI_INTA_POLARITY, MSI_INTA_POLARITY_HIGH); + + /* + * IRQ Edge Rising: 25:24 = 0x01 + * Traffic Class: 18:16 = 0x00 + * MSI ID: 4:0 = 0x00 + */ + for (i = 0; i < SAA716x_MSI_VECTORS; i++) + SAA716x_EPWR(MSI, MSI_CONFIG_REG[i], MSI_INT_POL_EDGE_RISE); + + /* get Status */ + ena_l = SAA716x_EPRD(MSI, MSI_INT_ENA_L); + ena_h = SAA716x_EPRD(MSI, MSI_INT_ENA_H); + sta_l = SAA716x_EPRD(MSI, MSI_INT_STATUS_L); + sta_h = SAA716x_EPRD(MSI, MSI_INT_STATUS_H); + + /* disable and clear enabled and asserted IRQ's */ + if (sta_l) + SAA716x_EPWR(MSI, MSI_INT_STATUS_CLR_L, sta_l); + + if (sta_h) + SAA716x_EPWR(MSI, MSI_INT_STATUS_CLR_H, sta_h); + + if (ena_l) + SAA716x_EPWR(MSI, MSI_INT_ENA_CLR_L, ena_l); + + if (ena_h) + SAA716x_EPWR(MSI, MSI_INT_ENA_CLR_H, ena_h); + + msleep(5); + + /* Check IRQ's really disabled */ + ena_l = SAA716x_EPRD(MSI, MSI_INT_ENA_L); + ena_h = SAA716x_EPRD(MSI, MSI_INT_ENA_H); + sta_l = SAA716x_EPRD(MSI, MSI_INT_STATUS_L); + sta_h = SAA716x_EPRD(MSI, MSI_INT_STATUS_H); + + if ((ena_l == 0) && (ena_h == 0) && (sta_l == 0) && (sta_h == 0)) { + dprintk(SAA716x_DEBUG, 1, "Interrupts ena_l <%02x> ena_h <%02x> sta_l <%02x> sta_h <%02x>", + ena_l, ena_h, sta_l, sta_h); + + return 0; + } else { + dprintk(SAA716x_DEBUG, 1, "I/O error"); + return -EIO; + } + + return 0; +} +EXPORT_SYMBOL_GPL(saa716x_msi_init); + +void saa716x_msiint_disable(struct saa716x_dev *saa716x) +{ + dprintk(SAA716x_DEBUG, 1, "Disabling Interrupts ..."); + + SAA716x_EPWR(MSI, MSI_INT_ENA_L, 0x0); + SAA716x_EPWR(MSI, MSI_INT_ENA_H, 0x0); + SAA716x_EPWR(MSI, MSI_INT_STATUS_CLR_L, 0xffffffff); + SAA716x_EPWR(MSI, MSI_INT_STATUS_CLR_L, 0x0000ffff); +} +EXPORT_SYMBOL_GPL(saa716x_msiint_disable); + + +/* Map the given vector Id to the hardware bitmask. */ +static void saa716x_map_vector(struct saa716x_dev *saa716x, int vector, u32 *mask_l, u32 *mask_h) +{ + u32 tmp = 1; + + if (vector < 32) { + /* Bits 0 - 31 */ + tmp <<= vector; + *mask_l = tmp; + *mask_h = 0; + } else { + /* Bits 32 - 48 */ + tmp <<= vector - 32; + *mask_l = 0; + *mask_h = tmp; + } +} + +int saa716x_add_irqvector(struct saa716x_dev *saa716x, + int vector, + enum saa716x_edge edge, + irqreturn_t (*handler)(int irq, void *dev_id), + char *desc) +{ + struct saa716x_msix_entry *msix_handler = NULL; + + u32 config, mask_l, mask_h, ena_l, ena_h; + + BUG_ON(saa716x == NULL); + BUG_ON(vector > SAA716x_MSI_VECTORS); + dprintk(SAA716x_DEBUG, 1, "Adding Vector %d <%s>", vector, vector_name[vector]); + + if ((vector > 32) && (vector < 49)) { + config = SAA716x_EPRD(MSI, MSI_CONFIG_REG[vector]); + config &= 0xfcffffff; /* clear polarity */ + + switch (edge) { + default: + case SAA716x_EDGE_RISING: + SAA716x_EPWR(MSI, MSI_CONFIG_REG[vector], config | 0x01000000); + break; + + case SAA716x_EDGE_FALLING: + SAA716x_EPWR(MSI, MSI_CONFIG_REG[vector], config | 0x02000000); + break; + + case SAA716x_EDGE_ANY: + SAA716x_EPWR(MSI, MSI_CONFIG_REG[vector], config | 0x03000000); + break; + } + } + + saa716x_map_vector(saa716x, vector, &mask_l, &mask_h); + + /* add callback */ + msix_handler = &saa716x->saa716x_msix_handler[saa716x->handlers]; + strcpy(msix_handler->desc, desc); + msix_handler->vector = vector; + msix_handler->handler = handler; + saa716x->handlers++; + + SAA716x_EPWR(MSI, MSI_INT_ENA_SET_L, mask_l); + SAA716x_EPWR(MSI, MSI_INT_ENA_SET_H, mask_h); + + ena_l = SAA716x_EPRD(MSI, MSI_INT_ENA_L); + ena_h = SAA716x_EPRD(MSI, MSI_INT_ENA_H); + dprintk(SAA716x_DEBUG, 1, "Interrupts ena_l <%02x> ena_h <%02x>", ena_l, ena_h); + + return 0; +} + +int saa716x_remove_irqvector(struct saa716x_dev *saa716x, int vector) +{ + struct saa716x_msix_entry *msix_handler; + int i; + u32 mask_l, mask_h; + + msix_handler = &saa716x->saa716x_msix_handler[saa716x->handlers]; + BUG_ON(msix_handler == NULL); + dprintk(SAA716x_DEBUG, 1, "Removing Vector %d <%s>", vector, vector_name[vector]); + + /* loop through the registered handlers */ + for (i = 0; i < saa716x->handlers; i++) { + + /* we found our vector */ + if (msix_handler->vector == vector) { + BUG_ON(msix_handler->handler == NULL); /* no handler yet */ + dprintk(SAA716x_DEBUG, 1, "Vector %d <%s> removed", + msix_handler->vector, + msix_handler->desc); + + /* check whether it is already released */ + if (msix_handler->handler) { + msix_handler->vector = 0; + msix_handler->handler = NULL; + saa716x->handlers--; + } + } + } + + saa716x_map_vector(saa716x, vector, &mask_l, &mask_h); + + /* disable vector */ + SAA716x_EPWR(MSI, MSI_INT_ENA_CLR_L, mask_l); + SAA716x_EPWR(MSI, MSI_INT_ENA_CLR_H, mask_h); + + return 0; +} diff --git a/drivers/media/common/saa716x/saa716x_msi.h b/drivers/media/common/saa716x/saa716x_msi.h new file mode 100644 index 0000000..8eb72d7 --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_msi.h @@ -0,0 +1,87 @@ +#ifndef __SAA716x_MSI_H +#define __SAA716x_MSI_H + +#define TAGACK_VI0_0 0x000 +#define TAGACK_VI0_1 0x001 +#define TAGACK_VI0_2 0x002 +#define TAGACK_VI1_0 0x003 +#define TAGACK_VI1_1 0x004 +#define TAGACK_VI1_2 0x005 +#define TAGACK_FGPI_0 0x006 +#define TAGACK_FGPI_1 0x007 +#define TAGACK_FGPI_2 0x008 +#define TAGACK_FGPI_3 0x009 +#define TAGACK_AI_0 0x00a +#define TAGACK_AI_1 0x00b +#define OVRFLW_VI0_0 0x00c +#define OVRFLW_VI0_1 0x00d +#define OVRFLW_VI0_2 0x00e +#define OVRFLW_VI1_0 0x00f +#define OVRFLW_VI1_1 0x010 +#define OVRFLW_VI1_2 0x011 +#define OVRFLW_FGPI_O 0x012 +#define OVRFLW_FGPI_1 0x013 +#define OVRFLW_FGPI_2 0x014 +#define OVRFLW_FGPI_3 0x015 +#define OVRFLW_AI_0 0x016 +#define OVRFLW_AI_1 0x017 +#define AVINT_VI0 0x018 +#define AVINT_VI1 0x019 +#define AVINT_FGPI_0 0x01a +#define AVINT_FGPI_1 0x01b +#define AVINT_FGPI_2 0x01c +#define AVINT_FGPI_3 0x01d +#define AVINT_AI_0 0x01e +#define AVINT_AI_1 0x01f +#define UNMAPD_TC_INT 0x020 +#define EXTINT_0 0x021 +#define EXTINT_1 0x022 +#define EXTINT_2 0x023 +#define EXTINT_3 0x024 +#define EXTINT_4 0x025 +#define EXTINT_5 0x026 +#define EXTINT_6 0x027 +#define EXTINT_7 0x028 +#define EXTINT_8 0x029 +#define EXTINT_9 0x02a +#define EXTINT_10 0x02b +#define EXTINT_11 0x02c +#define EXTINT_12 0x02d +#define EXTINT_13 0x02e +#define EXTINT_14 0x02f +#define EXTINT_15 0x030 +#define I2CINT_0 0x031 +#define I2CINT_1 0x032 + +#define SAA716x_TC0 0x000 +#define SAA716x_TC1 0x001 +#define SAA716x_TC2 0x002 +#define SAA716x_TC3 0x003 +#define SAA716x_TC4 0x004 +#define SAA716x_TC5 0x005 +#define SAA716x_TC6 0x006 +#define SAA716x_TC7 0x007 + + +enum saa716x_edge { + SAA716x_EDGE_RISING = 1, + SAA716x_EDGE_FALLING = 2, + SAA716x_EDGE_ANY = 3 +}; + +struct saa716x_dev; + +extern int saa716x_msi_event(struct saa716x_dev *saa716x, u32 stat_l, u32 stat_h); + +extern int saa716x_msi_init(struct saa716x_dev *saa716x); +extern void saa716x_msiint_disable(struct saa716x_dev *saa716x); + +extern int saa716x_add_irqvector(struct saa716x_dev *saa716x, + int vector, + enum saa716x_edge edge, + irqreturn_t (*handler)(int irq, void *dev_id), + char *desc); + +extern int saa716x_remove_irqvector(struct saa716x_dev *saa716x, int vector); + +#endif /* __SAA716x_MSI_H */ diff --git a/drivers/media/common/saa716x/saa716x_msi_reg.h b/drivers/media/common/saa716x/saa716x_msi_reg.h new file mode 100644 index 0000000..d9a12c7 --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_msi_reg.h @@ -0,0 +1,143 @@ +#ifndef __SAA716x_MSI_REG_H +#define __SAA716x_MSI_REG_H + +/* -------------- MSI Registers -------------- */ + +#define MSI_DELAY_TIMER 0x000 +#define MSI_DELAY_1CLK (0x00000001 << 0) +#define MSI_DELAY_2CLK (0x00000002 << 0) + +#define MSI_INTA_POLARITY 0x004 +#define MSI_INTA_POLARITY_HIGH (0x00000001 << 0) + +#define MSI_CONFIG0 0x008 +#define MSI_CONFIG1 0x00c +#define MSI_CONFIG2 0x010 +#define MSI_CONFIG3 0x014 +#define MSI_CONFIG4 0x018 +#define MSI_CONFIG5 0x01c +#define MSI_CONFIG6 0x020 +#define MSI_CONFIG7 0x024 +#define MSI_CONFIG8 0x028 +#define MSI_CONFIG9 0x02c +#define MSI_CONFIG10 0x030 +#define MSI_CONFIG11 0x034 +#define MSI_CONFIG12 0x038 +#define MSI_CONFIG13 0x03c +#define MSI_CONFIG14 0x040 +#define MSI_CONFIG15 0x044 +#define MSI_CONFIG16 0x048 +#define MSI_CONFIG17 0x04c +#define MSI_CONFIG18 0x050 +#define MSI_CONFIG19 0x054 +#define MSI_CONFIG20 0x058 +#define MSI_CONFIG21 0x05c +#define MSI_CONFIG22 0x060 +#define MSI_CONFIG23 0x064 +#define MSI_CONFIG24 0x068 +#define MSI_CONFIG25 0x06c +#define MSI_CONFIG26 0x070 +#define MSI_CONFIG27 0x074 +#define MSI_CONFIG28 0x078 +#define MSI_CONFIG29 0x07c +#define MSI_CONFIG30 0x080 +#define MSI_CONFIG31 0x084 +#define MSI_CONFIG32 0x088 +#define MSI_CONFIG33 0x08c +#define MSI_CONFIG34 0x090 +#define MSI_CONFIG35 0x094 +#define MSI_CONFIG36 0x098 +#define MSI_CONFIG37 0x09c +#define MSI_CONFIG38 0x0a0 +#define MSI_CONFIG39 0x0a4 +#define MSI_CONFIG40 0x0a8 +#define MSI_CONFIG41 0x0ac +#define MSI_CONFIG42 0x0b0 +#define MSI_CONFIG43 0x0b4 +#define MSI_CONFIG44 0x0b8 +#define MSI_CONFIG45 0x0bc +#define MSI_CONFIG46 0x0c0 +#define MSI_CONFIG47 0x0c4 +#define MSI_CONFIG48 0x0c8 +#define MSI_CONFIG49 0x0cc +#define MSI_CONFIG50 0x0d0 + +#define MSI_INT_POL_EDGE_RISE (0x00000001 << 24) +#define MSI_INT_POL_EDGE_FALL (0x00000002 << 24) +#define MSI_INT_POL_EDGE_ANY (0x00000003 << 24) +#define MSI_TC (0x00000007 << 16) +#define MSI_ID (0x0000000f << 0) + +#define MSI_INT_STATUS_L 0xfc0 +#define MSI_INT_TAGACK_VI0_0 (0x00000001 << 0) +#define MSI_INT_TAGACK_VI0_1 (0x00000001 << 1) +#define MSI_INT_TAGACK_VI0_2 (0x00000001 << 2) +#define MSI_INT_TAGACK_VI1_0 (0x00000001 << 3) +#define MSI_INT_TAGACK_VI1_1 (0x00000001 << 4) +#define MSI_INT_TAGACK_VI1_2 (0x00000001 << 5) +#define MSI_INT_TAGACK_FGPI_0 (0x00000001 << 6) +#define MSI_INT_TAGACK_FGPI_1 (0x00000001 << 7) +#define MSI_INT_TAGACK_FGPI_2 (0x00000001 << 8) +#define MSI_INT_TAGACK_FGPI_3 (0x00000001 << 9) +#define MSI_INT_TAGACK_AI_0 (0x00000001 << 10) +#define MSI_INT_TAGACK_AI_1 (0x00000001 << 11) +#define MSI_INT_OVRFLW_VI0_0 (0x00000001 << 12) +#define MSI_INT_OVRFLW_VI0_1 (0x00000001 << 13) +#define MSI_INT_OVRFLW_VI0_2 (0x00000001 << 14) +#define MSI_INT_OVRFLW_VI1_0 (0x00000001 << 15) +#define MSI_INT_OVRFLW_VI1_1 (0x00000001 << 16) +#define MSI_INT_OVRFLW_VI1_2 (0x00000001 << 17) +#define MSI_INT_OVRFLW_FGPI_0 (0x00000001 << 18) +#define MSI_INT_OVRFLW_FGPI_1 (0x00000001 << 19) +#define MSI_INT_OVRFLW_FGPI_2 (0x00000001 << 20) +#define MSI_INT_OVRFLW_FGPI_3 (0x00000001 << 21) +#define MSI_INT_OVRFLW_AI_0 (0x00000001 << 22) +#define MSI_INT_OVRFLW_AI_1 (0x00000001 << 23) +#define MSI_INT_AVINT_VI0 (0x00000001 << 24) +#define MSI_INT_AVINT_VI1 (0x00000001 << 25) +#define MSI_INT_AVINT_FGPI_0 (0x00000001 << 26) +#define MSI_INT_AVINT_FGPI_1 (0x00000001 << 27) +#define MSI_INT_AVINT_FGPI_2 (0x00000001 << 28) +#define MSI_INT_AVINT_FGPI_3 (0x00000001 << 29) +#define MSI_INT_AVINT_AI_0 (0x00000001 << 30) +#define MSI_INT_AVINT_AI_1 (0x00000001 << 31) + +#define MSI_INT_STATUS_H 0xfc4 +#define MSI_INT_UNMAPD_TC_INT (0x00000001 << 0) +#define MSI_INT_EXTINT_0 (0x00000001 << 1) +#define MSI_INT_EXTINT_1 (0x00000001 << 2) +#define MSI_INT_EXTINT_2 (0x00000001 << 3) +#define MSI_INT_EXTINT_3 (0x00000001 << 4) +#define MSI_INT_EXTINT_4 (0x00000001 << 5) +#define MSI_INT_EXTINT_5 (0x00000001 << 6) +#define MSI_INT_EXTINT_6 (0x00000001 << 7) +#define MSI_INT_EXTINT_7 (0x00000001 << 8) +#define MSI_INT_EXTINT_8 (0x00000001 << 9) +#define MSI_INT_EXTINT_9 (0x00000001 << 10) +#define MSI_INT_EXTINT_10 (0x00000001 << 11) +#define MSI_INT_EXTINT_11 (0x00000001 << 12) +#define MSI_INT_EXTINT_12 (0x00000001 << 13) +#define MSI_INT_EXTINT_13 (0x00000001 << 14) +#define MSI_INT_EXTINT_14 (0x00000001 << 15) +#define MSI_INT_EXTINT_15 (0x00000001 << 16) +#define MSI_INT_I2CINT_0 (0x00000001 << 17) +#define MSI_INT_I2CINT_1 (0x00000001 << 18) + +#define MSI_INT_STATUS_CLR_L 0xfc8 +#define MSI_INT_STATUS_CLR_H 0xfcc +#define MSI_INT_STATUS_SET_L 0xfd0 +#define MSI_INT_STATUS_SET_H 0xfd4 +#define MSI_INT_ENA_L 0xfd8 +#define MSI_INT_ENA_H 0xfdc +#define MSI_INT_ENA_CLR_L 0xfe0 +#define MSI_INT_ENA_CLR_H 0xfe4 +#define MSI_INT_ENA_SET_L 0xfe8 +#define MSI_INT_ENA_SET_H 0xfec + +#define MSI_SW_RST 0xff0 +#define MSI_SW_RESET (0x0001 << 0) + +#define MSI_MODULE_ID 0xffc + + +#endif /* __SAA716x_MSI_REG_H */ diff --git a/drivers/media/common/saa716x/saa716x_pci.c b/drivers/media/common/saa716x/saa716x_pci.c new file mode 100644 index 0000000..7fa6bad --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_pci.c @@ -0,0 +1,275 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "saa716x_spi.h" +#include "saa716x_msi.h" +#include "saa716x_priv.h" + +#define DRIVER_NAME "SAA716x Core" + +static irqreturn_t saa716x_msi_handler(int irq, void *dev_id) +{ + return IRQ_HANDLED; +} + +static int saa716x_enable_msi(struct saa716x_dev *saa716x) +{ + struct pci_dev *pdev = saa716x->pdev; + int err; + + err = pci_enable_msi(pdev); + if (err) { + dprintk(SAA716x_ERROR, 1, "MSI enable failed <%d>", err); + return err; + } + + return err; +} + +static int saa716x_enable_msix(struct saa716x_dev *saa716x) +{ + struct pci_dev *pdev = saa716x->pdev; + int i, ret = 0; + + for (i = 0; i < SAA716x_MSI_MAX_VECTORS; i++) + saa716x->msix_entries[i].entry = i; + + ret = pci_enable_msix(pdev, saa716x->msix_entries, SAA716x_MSI_MAX_VECTORS); + if (ret < 0) + dprintk(SAA716x_ERROR, 1, "MSI-X request failed <%d>", ret); + if (ret > 0) + dprintk(SAA716x_ERROR, 1, "Request exceeds available IRQ's <%d>", ret); + + return ret; +} + +static int saa716x_request_irq(struct saa716x_dev *saa716x) +{ + struct pci_dev *pdev = saa716x->pdev; + struct saa716x_config *config = saa716x->config; + int i, ret = 0; + + if (saa716x->int_type == MODE_MSI) { + dprintk(SAA716x_DEBUG, 1, "Using MSI mode"); + ret = saa716x_enable_msi(saa716x); + } else if (saa716x->int_type == MODE_MSI_X) { + dprintk(SAA716x_DEBUG, 1, "Using MSI-X mode"); + ret = saa716x_enable_msix(saa716x); + } + + if (ret) { + dprintk(SAA716x_ERROR, 1, "INT-A Mode"); + saa716x->int_type = MODE_INTA; + } + + if (saa716x->int_type == MODE_MSI) { + ret = request_irq(pdev->irq, + config->irq_handler, + 0, + DRIVER_NAME, + saa716x); + + if (ret) { + pci_disable_msi(pdev); + dprintk(SAA716x_ERROR, 1, "MSI registration failed"); + ret = -EIO; + } + } + + if (saa716x->int_type == MODE_MSI_X) { + for (i = 0; SAA716x_MSI_MAX_VECTORS; i++) { + ret = request_irq(saa716x->msix_entries[i].vector, + saa716x->saa716x_msix_handler[i].handler, + IRQF_SHARED, + saa716x->saa716x_msix_handler[i].desc, + saa716x); + + dprintk(SAA716x_ERROR, 1, "%s @ 0x%p", saa716x->saa716x_msix_handler[i].desc, saa716x->saa716x_msix_handler[i].handler); + if (ret) { + dprintk(SAA716x_ERROR, 1, "%s MSI-X-%d registration failed <%d>", saa716x->saa716x_msix_handler[i].desc, i, ret); + return -1; + } + } + } + + if (saa716x->int_type == MODE_INTA) { + ret = request_irq(pdev->irq, + config->irq_handler, + IRQF_SHARED, + DRIVER_NAME, + saa716x); + if (ret < 0) { + dprintk(SAA716x_ERROR, 1, "SAA716x IRQ registration failed <%d>", ret); + ret = -ENODEV; + } + } + + return ret; +} + +static void saa716x_free_irq(struct saa716x_dev *saa716x) +{ + struct pci_dev *pdev = saa716x->pdev; + int i, vector; + + if (saa716x->int_type == MODE_MSI_X) { + + for (i = 0; i < SAA716x_MSI_MAX_VECTORS; i++) { + vector = saa716x->msix_entries[i].vector; + free_irq(vector, saa716x); + } + + pci_disable_msix(pdev); + + } else { + free_irq(pdev->irq, saa716x); + if (saa716x->int_type == MODE_MSI) + pci_disable_msi(pdev); + } +} + +int saa716x_pci_init(struct saa716x_dev *saa716x) +{ + struct pci_dev *pdev = saa716x->pdev; + int err = 0, ret = -ENODEV, i, use_dac, pm_cap; + u32 msi_cap; + u8 revision; + + dprintk(SAA716x_ERROR, 1, "found a %s PCIe card", saa716x->config->model_name); + + err = pci_enable_device(pdev); + if (err != 0) { + ret = -ENODEV; + dprintk(SAA716x_ERROR, 1, "ERROR: PCI enable failed (%i)", err); + goto fail0; + } + + if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { + use_dac = 1; + err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); + if (err) { + dprintk(SAA716x_ERROR, 1, "Unable to obtain 64bit DMA"); + goto fail1; + } + } else if ((err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) != 0) { + dprintk(SAA716x_ERROR, 1, "Unable to obtain 32bit DMA"); + goto fail1; + } + + pci_set_master(pdev); + + pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM); + if (pm_cap == 0) { + dprintk(SAA716x_ERROR, 1, "Cannot find Power Management Capability"); + err = -EIO; + goto fail1; + } + + if (!request_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0), + DRIVER_NAME)) { + + dprintk(SAA716x_ERROR, 1, "BAR0 Request failed"); + ret = -ENODEV; + goto fail1; + } + saa716x->mmio = ioremap(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + + if (!saa716x->mmio) { + dprintk(SAA716x_ERROR, 1, "Mem 0 remap failed"); + ret = -ENODEV; + goto fail2; + } + + for (i = 0; i < SAA716x_MSI_MAX_VECTORS; i++) + saa716x->msix_entries[i].entry = i; + + err = saa716x_request_irq(saa716x); + if (err < 0) { + dprintk(SAA716x_ERROR, 1, "SAA716x IRQ registration failed, err=%d", err); + ret = -ENODEV; + goto fail3; + } + + pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); + pci_read_config_dword(pdev, 0x40, &msi_cap); + + saa716x->revision = revision; + + dprintk(SAA716x_ERROR, 0, " SAA%02x Rev %d [%04x:%04x], ", + saa716x->pdev->device, + revision, + saa716x->pdev->subsystem_vendor, + saa716x->pdev->subsystem_device); + + dprintk(SAA716x_ERROR, 0, + "irq: %d,\n mmio: 0x%p\n", + saa716x->pdev->irq, + saa716x->mmio); + + dprintk(SAA716x_ERROR, 0, " SAA%02x %sBit, MSI %s, MSI-X=%d msgs", + saa716x->pdev->device, + (((msi_cap >> 23) & 0x01) == 1 ? "64":"32"), + (((msi_cap >> 16) & 0x01) == 1 ? "Enabled" : "Disabled"), + (1 << ((msi_cap >> 17) & 0x07))); + + dprintk(SAA716x_ERROR, 0, "\n"); + + pci_set_drvdata(pdev, saa716x); + + return 0; + +fail3: + dprintk(SAA716x_ERROR, 1, "Err: IO Unmap"); + if (saa716x->mmio) + iounmap(saa716x->mmio); +fail2: + dprintk(SAA716x_ERROR, 1, "Err: Release regions"); + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + +fail1: + dprintk(SAA716x_ERROR, 1, "Err: Disabling device"); + pci_disable_device(pdev); + +fail0: + pci_set_drvdata(pdev, NULL); + return ret; +} +EXPORT_SYMBOL_GPL(saa716x_pci_init); + +void saa716x_pci_exit(struct saa716x_dev *saa716x) +{ + struct pci_dev *pdev = saa716x->pdev; + + saa716x_free_irq(saa716x); + + dprintk(SAA716x_NOTICE, 1, "SAA%02x mem0: 0x%p", + saa716x->pdev->device, + saa716x->mmio); + + if (saa716x->mmio) { + iounmap(saa716x->mmio); + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + } + + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); +} +EXPORT_SYMBOL_GPL(saa716x_pci_exit); + +MODULE_DESCRIPTION("SAA716x bridge driver"); +MODULE_AUTHOR("Manu Abraham"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/common/saa716x/saa716x_phi.c b/drivers/media/common/saa716x/saa716x_phi.c new file mode 100644 index 0000000..7df9a98 --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_phi.c @@ -0,0 +1,152 @@ +#include + +#include "saa716x_mod.h" + +#include "saa716x_phi_reg.h" + +#include "saa716x_spi.h" +#include "saa716x_phi.h" +#include "saa716x_priv.h" + +u32 PHI_0_REGS[] = { + PHI_0_MODE, + PHI_0_0_CONFIG, + PHI_0_1_CONFIG, + PHI_0_2_CONFIG, + PHI_0_3_CONFIG +}; + +u32 PHI_1_REGS[] = { + PHI_1_MODE, + PHI_1_0_CONFIG, + PHI_1_1_CONFIG, + PHI_1_2_CONFIG, + PHI_1_3_CONFIG, + PHI_1_4_CONFIG, + PHI_1_5_CONFIG, + PHI_1_6_CONFIG, + PHI_1_7_CONFIG +}; + +#define PHI_BASE(__port) (( \ + (__port == PHI_1) ? \ + PHI_1_BASE : \ + PHI_0_BASE \ +)) + +#define PHI_APERTURE(_port) (( \ + (__port == PHI_1) ? \ + PHI_1_APERTURE: \ + PHI_0_APERTURE \ +)) + +#define PHI_REG(__port, __reg) (( \ + (__port == PHI_1) ? \ + PHI_1_REGS[__reg] : \ + PHI_0_REGS[__reg] \ +)) + +#define PHI_SLAVE(__port, __slave) (( \ + PHI_BASE(__port) + (__slave * (PHI_APERTURE(__port))) \ +)) + +/* // Read SAA716x registers + * SAA716x_EPRD(PHI_0, PHI_REG(__port, __reg)) + * SAA716x_EPWR(PHI_1, PHI_REG(__port, __reg), __data) + * + * // Read slave registers + * SAA716x_EPRD(PHI_0, PHI_SLAVE(__port, __slave, __offset)) + * SAA716x_EPWR(PHI_1, PHI_SLAVE(__port, __slave, _offset), __data) + */ + +int saa716x_init_phi(struct saa716x_dev *saa716x, u32 port, u8 slave) +{ + int i; + + /* Reset */ + SAA716x_EPWR(PHI_0, PHI_SW_RST, 0x1); + + for (i = 0; i < 20; i++) { + msleep(1); + if (!(SAA716x_EPRD(PHI_0, PHI_SW_RST))) + break; + } + + return 0; +} + +int saa716x_phi_init(struct saa716x_dev *saa716x) +{ + uint32_t value; + + /* init PHI 0 to FIFO mode */ + value = 0; + value |= PHI_FIFO_MODE; + SAA716x_EPWR(PHI_0, PHI_0_MODE, value); + + value = 0; + value |= 0x02; /* chip select 1 */ + value |= 0x00 << 8; /* ready mask */ + value |= 0x03 << 12; /* strobe time */ + value |= 0x06 << 20; /* cycle time */ + SAA716x_EPWR(PHI_0, PHI_0_0_CONFIG, value); + + /* init PHI 1 to SRAM mode, auto increment on */ + value = 0; + value |= PHI_AUTO_INCREMENT; + SAA716x_EPWR(PHI_0, PHI_1_MODE, value); + + value = 0; + value |= 0x01; /* chip select 0 */ + value |= 0x00 << 8; /* ready mask */ + value |= 0x03 << 12; /* strobe time */ + value |= 0x05 << 20; /* cycle time */ + SAA716x_EPWR(PHI_0, PHI_1_0_CONFIG, value); + + value = 0; + value |= PHI_ALE_POL; /* ALE is active high */ + SAA716x_EPWR(PHI_0, PHI_POLARITY, value); + + SAA716x_EPWR(PHI_0, PHI_TIMEOUT, 0x2a); + + return 0; +} +EXPORT_SYMBOL_GPL(saa716x_phi_init); + +int saa716x_phi_write(struct saa716x_dev *saa716x, u32 address, const u8 * data, int length) +{ + int i; + + for (i = 0; i < length; i += 4) { + SAA716x_EPWR(PHI_1, address, *((u32 *) &data[i])); + address += 4; + } + + return 0; +} +EXPORT_SYMBOL_GPL(saa716x_phi_write); + +int saa716x_phi_read(struct saa716x_dev *saa716x, u32 address, u8 * data, int length) +{ + int i; + + for (i = 0; i < length; i += 4) { + *((u32 *) &data[i]) = SAA716x_EPRD(PHI_1, address); + address += 4; + } + + return 0; +} +EXPORT_SYMBOL_GPL(saa716x_phi_read); + +int saa716x_phi_write_fifo(struct saa716x_dev *saa716x, const u8 * data, int length) +{ + int i; + + for (i = 0; i < length; i += 4) { + SAA716x_EPWR(PHI_0, PHI_0_0_RW_0, *((u32 *) &data[i])); + } + + return 0; +} +EXPORT_SYMBOL_GPL(saa716x_phi_write_fifo); diff --git a/drivers/media/common/saa716x/saa716x_phi.h b/drivers/media/common/saa716x/saa716x_phi.h new file mode 100644 index 0000000..ff5cda2 --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_phi.h @@ -0,0 +1,39 @@ +#ifndef __SAA716x_PHI_H +#define __SAA716x_PHI_H + +/* PHI SLAVE */ +#define PHI_SLAVE_0 0 +#define PHI_SLAVE_1 1 +#define PHI_SLAVE_2 2 +#define PHI_SLAVE_3 3 +#define PHI_SLAVE_4 4 +#define PHI_SLAVE_5 5 +#define PHI_SLAVE_6 6 +#define PHI_SLAVE_7 7 + +/* PHI_REG */ +#define PHI_MODE 0 +#define PHI_CONFIG_0 1 +#define PHI_CONFIG_1 2 +#define PHI_CONFIG_2 3 +#define PHI_CONFIG_3 4 +#define PHI_CONFIG_4 5 +#define PHI_CONFIG_5 6 +#define PHI_CONFIG_6 7 +#define PHI_CONFIG_7 8 + +#define PHI_0_BASE 0x1000 +#define PHI_0_APERTURE 0x0800 + +#define PHI_1_BASE 0x0000 +#define PHI_1_APERTURE 0xfffc + +struct saa716x_dev; + +extern int saa716x_init_phi(struct saa716x_dev *saa716x, u32 port, u8 slave); +extern int saa716x_phi_init(struct saa716x_dev *saa716x); +extern int saa716x_phi_write(struct saa716x_dev *saa716x, u32 address, const u8 *data, int length); +extern int saa716x_phi_read(struct saa716x_dev *saa716x, u32 address, u8 *data, int length); +extern int saa716x_phi_write_fifo(struct saa716x_dev *saa716x, const u8 * data, int length); + +#endif /* __SAA716x_PHI_H */ diff --git a/drivers/media/common/saa716x/saa716x_phi_reg.h b/drivers/media/common/saa716x/saa716x_phi_reg.h new file mode 100644 index 0000000..08f0aa7 --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_phi_reg.h @@ -0,0 +1,100 @@ +#ifndef __SAA716x_PHI_REG_H +#define __SAA716x_PHI_REG_H + +/* -------------- PHI_0 Registers -------------- */ + +#define PHI_0_MODE 0x0000 +#define PHI_0_0_CONFIG 0x0008 +#define PHI_0_1_CONFIG 0x000c +#define PHI_0_2_CONFIG 0x0010 +#define PHI_0_3_CONFIG 0x0014 + +#define PHI_POLARITY 0x0038 +#define PHI_TIMEOUT 0x003c +#define PHI_SW_RST 0x0ff0 + +#define PHI_0_0_RW_0 0x1000 +#define PHI_0_0_RW_511 0x17fc + +#define PHI_0_1_RW_0 0x1800 +#define PHI_0_1_RW_511 0x1ffc + +#define PHI_0_2_RW_0 0x2000 +#define PHI_0_2_RW_511 0x27fc + +#define PHI_0_3_RW_0 0x2800 +#define PHI_0_3_RW_511 0x2ffc + +#define PHI_CSN_DEASSERT (0x00000001 << 2) +#define PHI_AUTO_INCREMENT (0x00000001 << 1) +#define PHI_FIFO_MODE (0x00000001 << 0) + +#define PHI_DELAY_RD_WR (0x0000001f << 27) +#define PHI_EXTEND_RDY3 (0x00000003 << 25) +#define PHI_EXTEND_RDY2 (0x00000003 << 23) +#define PHI_EXTEND_RDY1 (0x00000003 << 21) +#define PHI_EXTEND_RDY0 (0x00000003 << 19) +#define PHI_RDY3_OD (0x00000001 << 18) +#define PHI_RDY2_OD (0x00000001 << 17) +#define PHI_RDY1_OD (0x00000001 << 16) +#define PHI_RDY0_OD (0x00000001 << 15) +#define PHI_ALE_POL (0x00000001 << 14) +#define PHI_WRN_POL (0x00000001 << 13) +#define PHI_RDN_POL (0x00000001 << 12) +#define PHI_RDY3_POL (0x00000001 << 11) +#define PHI_RDY2_POL (0x00000001 << 10) +#define PHI_RDY1_POL (0x00000001 << 9) +#define PHI_RDY0_POL (0x00000001 << 8) +#define PHI_CSN7_POL (0x00000001 << 7) +#define PHI_CSN6_POL (0x00000001 << 6) +#define PHI_CSN5_POL (0x00000001 << 5) +#define PHI_CSN4_POL (0x00000001 << 4) +#define PHI_CSN3_POL (0x00000001 << 3) +#define PHI_CSN2_POL (0x00000001 << 2) +#define PHI_CSN1_POL (0x00000001 << 1) +#define PHI_CSN0_POL (0x00000001 << 0) + +/* -------------- PHI_1 Registers -------------- */ + +#define PHI_1 0x00020000 + +#define PHI_1_MODE 0x00004 +#define PHI_1_0_CONFIG 0x00018 +#define PHI_1_1_CONFIG 0x0001c +#define PHI_1_2_CONFIG 0x00020 +#define PHI_1_3_CONFIG 0x00024 +#define PHI_1_4_CONFIG 0x00028 +#define PHI_1_5_CONFIG 0x0002c +#define PHI_1_6_CONFIG 0x00030 +#define PHI_1_7_CONFIG 0x00034 + +#define PHI_1_0_RW_0 0x00000 +#define PHI_1_0_RW_16383 0x0fffc + +#define PHI_1_1_RW_0 0x1000 +#define PHI_1_1_RW_16383 0x1ffc + +#define PHI_1_2_RW_0 0x2000 +#define PHI_1_2_RW_16383 0x2ffc + +#define PHI_1_3_RW_0 0x3000 +#define PHI_1_3_RW_16383 0x3ffc + +#define PHI_1_4_RW_0 0x4000 +#define PHI_1_4_RW_16383 0x4ffc + +#define PHI_1_5_RW_0 0x5000 +#define PHI_1_5_RW_16383 0x5ffc + +#define PHI_1_6_RW_0 0x6000 +#define PHI_1_6_RW_16383 0x6ffc + +#define PHI_1_7_RW_0 0x7000 +#define PHI_1_7_RW_16383 0x7ffc + + +/* BAR = 20 bits */ +/* -------------- PHI1 Registers -------------- */ + + +#endif /* __SAA716x_PHI_REG_H */ diff --git a/drivers/media/common/saa716x/saa716x_priv.h b/drivers/media/common/saa716x/saa716x_priv.h new file mode 100644 index 0000000..1ad1d9c --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_priv.h @@ -0,0 +1,194 @@ +#ifndef __SAA716x_PRIV_H +#define __SAA716x_PRIV_H + +#include +#include +#include +#include +#include + +#include +#include +#include +#include "saa716x_i2c.h" +#include "saa716x_boot.h" +#include "saa716x_cgu.h" +#include "saa716x_dma.h" +#include "saa716x_fgpi.h" + +#include "dvbdev.h" +#include "dvb_demux.h" +#include "dmxdev.h" +#include "dvb_frontend.h" +#include "dvb_net.h" + +#define SAA716x_ERROR 0 +#define SAA716x_NOTICE 1 +#define SAA716x_INFO 2 +#define SAA716x_DEBUG 3 + +#define SAA716x_DEV (saa716x)->num +#define SAA716x_VERBOSE (saa716x)->verbose +#define SAA716x_MAX_ADAPTERS 4 + +#define dprintk(__x, __y, __fmt, __arg...) do { \ + if (__y) { \ + if ((SAA716x_VERBOSE > SAA716x_ERROR) && (SAA716x_VERBOSE > __x)) \ + printk(KERN_ERR "%s (%d): " __fmt "\n" , __func__ , SAA716x_DEV , ##__arg); \ + else if ((SAA716x_VERBOSE > SAA716x_NOTICE) && (SAA716x_VERBOSE > __x)) \ + printk(KERN_NOTICE "%s (%d): " __fmt "\n" , __func__ , SAA716x_DEV , ##__arg); \ + else if ((SAA716x_VERBOSE > SAA716x_INFO) && (SAA716x_VERBOSE > __x)) \ + printk(KERN_INFO "%s (%d): " __fmt "\n" , __func__ , SAA716x_DEV , ##__arg); \ + else if ((SAA716x_VERBOSE > SAA716x_DEBUG) && (SAA716x_VERBOSE > __x)) \ + printk(KERN_DEBUG "%s (%d): " __fmt "\n" , __func__ , SAA716x_DEV , ##__arg); \ + } else { \ + if (SAA716x_VERBOSE > __x) \ + printk(__fmt , ##__arg); \ + } \ +} while(0) + + +#define NXP_SEMICONDUCTOR 0x1131 +#define SAA7160 0x7160 +#define SAA7161 0x7161 +#define SAA7162 0x7162 + +#define NXP_REFERENCE_BOARD 0x1131 + +#define MAKE_ENTRY(__subven, __subdev, __chip, __configptr) { \ + .vendor = NXP_SEMICONDUCTOR, \ + .device = (__chip), \ + .subvendor = (__subven), \ + .subdevice = (__subdev), \ + .driver_data = (unsigned long) (__configptr) \ +} + +#define SAA716x_EPWR(__offst, __addr, __data) writel((__data), (saa716x->mmio + (__offst + __addr))) +#define SAA716x_EPRD(__offst, __addr) readl((saa716x->mmio + (__offst + __addr))) + +#define SAA716x_RCWR(__offst, __addr, __data) writel((__data), (saa716x->mmio + (__offst + __addr))) +#define SAA716x_RCRD(__offst, __addr) readl((saa716x->mmio + (__offst + __addr))) + + +#define SAA716x_MSI_MAX_VECTORS 16 + +struct saa716x_msix_entry { + int vector; + u8 desc[32]; + irqreturn_t (*handler)(int irq, void *dev_id); +}; + +struct saa716x_dev; +struct saa716x_adapter; +struct saa716x_spi_config; + +struct saa716x_adap_config { + u32 ts_port; + void (*worker)(unsigned long); +}; + +struct saa716x_config { + char *model_name; + char *dev_type; + + enum saa716x_boot_mode boot_mode; + + int adapters; + int frontends; + + int (*frontend_attach)(struct saa716x_adapter *adapter, int count); + irqreturn_t (*irq_handler)(int irq, void *dev_id); + + struct saa716x_adap_config adap_config[SAA716x_MAX_ADAPTERS]; + enum saa716x_i2c_rate i2c_rate; + enum saa716x_i2c_mode i2c_mode; +}; + +struct saa716x_adapter { + struct dvb_adapter dvb_adapter; + struct dvb_frontend *fe; + struct dvb_demux demux; + struct dmxdev dmxdev; + struct dmx_frontend fe_hw; + struct dmx_frontend fe_mem; + struct dvb_net dvb_net; + + struct saa716x_dev *saa716x; + + u8 feeds; + u8 count; +}; + +struct saa716x_dev { + struct saa716x_config *config; + struct pci_dev *pdev; + + int num; /* device count */ + int verbose; + + u8 revision; + + /* PCI */ + void __iomem *mmio; + +#define MODE_INTA 0 +#define MODE_MSI 1 +#define MODE_MSI_X 2 + u8 int_type; + + struct msix_entry msix_entries[SAA716x_MSI_MAX_VECTORS]; + struct saa716x_msix_entry saa716x_msix_handler[56]; + u8 handlers; /* no. of active handlers */ + + /* I2C */ + struct saa716x_i2c i2c[2]; + u32 i2c_rate; /* init time */ + u32 I2C_DEV[2]; + + struct saa716x_spi_state *saa716x_spi; + struct saa716x_spi_config spi_config; + + struct saa716x_adapter saa716x_adap[SAA716x_MAX_ADAPTERS]; + struct mutex adap_lock; + struct saa716x_cgu cgu; + + spinlock_t gpio_lock; + /* DMA */ + + struct saa716x_fgpi_stream_port fgpi[4]; + + u32 id_offst; + u32 id_len; + void *priv; + + /* remote control */ + void *ir_priv; +}; + +/* PCI */ +extern int saa716x_pci_init(struct saa716x_dev *saa716x); +extern void saa716x_pci_exit(struct saa716x_dev *saa716x); + +/* MSI */ +extern int saa716x_msi_init(struct saa716x_dev *saa716x); +extern void saa716x_msi_exit(struct saa716x_dev *saa716x); +extern void saa716x_msiint_disable(struct saa716x_dev *saa716x); + +/* DMA */ +extern int saa716x_dma_init(struct saa716x_dev *saa716x); +extern void saa716x_dma_exit(struct saa716x_dev *saa716x); + +/* AUDIO */ +extern int saa716x_audio_init(struct saa716x_dev *saa716x); +extern void saa716x_audio_exit(struct saa716x_dev *saa716x); + +/* Boot */ +extern int saa716x_core_boot(struct saa716x_dev *saa716x); +extern int saa716x_jetpack_init(struct saa716x_dev *saa716x); + +/* Remote control */ +extern int saa716x_ir_init(struct saa716x_dev *saa716x); +extern void saa716x_ir_exit(struct saa716x_dev *saa716x); +extern void saa716x_ir_handler(struct saa716x_dev *saa716x, u32 ir_cmd); + +#endif /* __SAA716x_PRIV_H */ diff --git a/drivers/media/common/saa716x/saa716x_reg.h b/drivers/media/common/saa716x/saa716x_reg.h new file mode 100644 index 0000000..effd966 --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_reg.h @@ -0,0 +1,1279 @@ +#ifndef __SAA716x_REG_H +#define __SAA716x_REG_H + +/* BAR = 17 bits */ +/* + VI0 0x00000000 + VI1 0x00001000 + FGPI0 0x00002000 + FGPI1 0x00003000 + FGPI2 0x00004000 + FGPI3 0x00005000 + AI0 0x00006000 + AI1 0x00007000 + BAM 0x00008000 + MMU 0x00009000 + MSI 0x0000a000 + I2C_B 0x0000b000 + I2C_A 0x0000c000 + SPI 0x0000d000 + GPIO 0x0000e000 + PHI_0 0x0000f000 + CGU 0x00013000 + DCS 0x00014000 + GREG 0x00012000 + + PHI_1 0x00020000 +*/ + +/* -------------- VIP Registers -------------- */ + +#define VI0 0x00000000 +#define VI1 0x00001000 + +#define VI_MODE 0x000 +#define VID_CFEN (0x00000003 << 30) +#define VID_OSM (0x00000001 << 29) +#define VID_FSEQ (0x00000001 << 28) +#define AUX_CFEN (0x00000003 << 26) +#define AUX_OSM (0x00000001 << 25) +#define AUX_FSEQ (0x00000001 << 24) +#define AUX_ANC_DATA (0x00000003 << 22) +#define AUX_ANC_RAW (0x00000001 << 21) +#define RST_ON_ERR (0x00000001 << 17) +#define SOFT_RESET (0x00000001 << 16) +#define IFF_CLAMP (0x00000001 << 14) +#define IFF_MODE (0x00000003 << 12) +#define DFF_CLAMP (0x00000001 << 10) +#define DFF_MODE (0x00000003 << 8) +#define HSP_CLAMP (0x00000001 << 3) +#define HSP_RGB (0x00000001 << 2) +#define HSP_MODE (0x00000003 << 0) + +#define RCRB_CTRL 0x004 +#define RCRB_CFG_ADDR 0x008 +#define RCRB_CFG_EXT_ADDR 0x00c +#define RCRB_IO_ADDR 0x010 +#define RCRB_MEM_LADDR 0x014 +#define RCRB_MEM_UADDR 0x018 +#define RCRB_DATA 0x01c +#define RCRB_MASK 0x020 +#define RCRB_MSG_HDR 0x040 +#define RCRB_MSG_PL0 0x044 +#define RCRB_MSG_PL1 0x048 + +#define ID_MASK0 0x020 +#define VI_ID_MASK_0 (0x000000ff << 8) +#define VI_DATA_ID_0 (0x000000ff << 0) + +#define ID_MASK1 0x024 +#define VI_ID_MASK_1 (0x000000ff << 8) +#define VI_DATA_ID_1 (0x000000ff << 0) + +#define VIP_LINE_THRESH 0x040 +#define VI_LCTHR (0x000007ff << 0) + +#define VIN_FORMAT 0x100 +#define VI_VSRA (0x00000003 << 30) +#define VI_SYNCHD (0x00000001 << 25) +#define VI_DUAL_STREAM (0x00000001 << 24) +#define VI_NHDAUX (0x00000001 << 20) +#define VI_NPAR (0x00000001 << 19) +#define VI_VSEL (0x00000003 << 14) +#define VI_TWOS (0x00000001 << 13) +#define VI_TPG (0x00000001 << 12) +#define VI_FREF (0x00000001 << 10) +#define VI_FTGL (0x00000001 << 9) +#define VI_SF (0x00000001 << 3) +#define VI_FZERO (0x00000001 << 2) +#define VI_REVS (0x00000001 << 1) +#define VI_REHS (0x00000001 << 0) + +#define TC76543210 0x800 +#define TCFEDCBA98 0x804 +#define PHYCFG 0x900 +#define CONFIG 0xfd4 +#define INT_ENABLE_CLR 0xfd8 +#define INT_ENABLE_SET 0xfdc + + +#define INT_STATUS 0xfe0 +#define VI_STAT_FID_AUX (0x00000001 << 31) +#define VI_STAT_FID_VID (0x00000001 << 30) +#define VI_STAT_FID_VPI (0x00000001 << 29) +#define VI_STAT_LINE_COUNT (0x00000fff << 16) +#define VI_STAT_AUX_OVRFLW (0x00000001 << 9) +#define VI_STAT_VID_OVRFLW (0x00000001 << 8) +#define VI_STAT_WIN_SEQBRK (0x00000001 << 7) +#define VI_STAT_FID_SEQBRK (0x00000001 << 6) +#define VI_STAT_LINE_THRESH (0x00000001 << 5) +#define VI_STAT_AUX_WRAP (0x00000001 << 4) +#define VI_STAT_AUX_START_IN (0x00000001 << 3) +#define VI_STAT_AUX_END_OUT (0x00000001 << 2) +#define VI_STAT_VID_START_IN (0x00000001 << 1) +#define VI_STAT_VID_END_OUT (0x00000001 << 0) + +#define INT_ENABLE 0xfe4 +#define VI_ENABLE_AUX_OVRFLW (0x00000001 << 9) +#define VI_ENABLE_VID_OVRFLW (0x00000001 << 8) +#define VI_ENABLE_WIN_SEQBRK (0x00000001 << 7) +#define VI_ENABLE_FID_SEQBRK (0x00000001 << 6) +#define VI_ENABLE_LINE_THRESH (0x00000001 << 5) +#define VI_ENABLE_AUX_WRAP (0x00000001 << 4) +#define VI_ENABLE_AUX_START_IN (0x00000001 << 3) +#define VI_ENABLE_AUX_END_OUT (0x00000001 << 2) +#define VI_ENABLE_VID_START_IN (0x00000001 << 1) +#define VI_ENABLE_VID_END_OUT (0x00000001 << 0) + +#define INT_CLR_STATUS 0xfe8 +#define VI_CLR_STATUS_AUX_OVRFLW (0x00000001 << 9) +#define VI_CLR_STATUS_VID_OVRFLW (0x00000001 << 8) +#define VI_CLR_STATUS_WIN_SEQBRK (0x00000001 << 7) +#define VI_CLR_STATUS_FID_SEQBRK (0x00000001 << 6) +#define VI_CLR_STATUS_LINE_THRESH (0x00000001 << 5) +#define VI_CLR_STATUS_AUX_WRAP (0x00000001 << 4) +#define VI_CLR_STATUS_AUX_START_IN (0x00000001 << 3) +#define VI_CLR_STATUS_AUX_END_OUT (0x00000001 << 2) +#define VI_CLR_STATUS_VID_START_IN (0x00000001 << 1) +#define VI_CLR_STATUS_VID_END_OUT (0x00000001 << 0) + +#define INT_SET_STATUS 0xfec +#define VI_SET_STATUS_AUX_OVRFLW (0x00000001 << 9) +#define VI_SET_STATUS_VID_OVRFLW (0x00000001 << 8) +#define VI_SET_STATUS_WIN_SEQBRK (0x00000001 << 7) +#define VI_SET_STATUS_FID_SEQBRK (0x00000001 << 6) +#define VI_SET_STATUS_LINE_THRESH (0x00000001 << 5) +#define VI_SET_STATUS_AUX_WRAP (0x00000001 << 4) +#define VI_SET_STATUS_AUX_START_IN (0x00000001 << 3) +#define VI_SET_STATUS_AUX_END_OUT (0x00000001 << 2) +#define VI_SET_STATUS_VID_START_IN (0x00000001 << 1) +#define VI_SET_STATUS_VID_END_OUT (0x00000001 << 0) + +#define VIP_POWER_DOWN 0xff4 +#define VI_PWR_DWN (0x00000001 << 31) + + + + +/* -------------- FGPI Registers -------------- */ + +#define FGPI0 0x00002000 +#define FGPI1 0x00003000 +#define FGPI2 0x00004000 +#define FGPI3 0x00005000 + +#define FGPI_CONTROL 0x000 +#define FGPI_CAPTURE_ENABLE_2 (0x00000001 << 13) +#define FGPI_CAPTURE_ENABLE_1 (0x00000001 << 12) +#define FGPI_MODE (0x00000001 << 11) +#define FGPI_SAMPLE_SIZE (0x00000003 << 8) +#define FGPI_BUF_SYNC_MSG_STOP (0x00000003 << 5) +#define FGPI_REC_START_MSG_START (0x00000003 << 2) +#define FGPI_TSTAMP_SELECT (0x00000001 << 1) +#define FGPI_VAR_LENGTH (0x00000001 << 0) + +#define FGPI_BASE_1 0x004 +#define FGPI_BASE_2 0x008 +#define FGPI_SIZE 0x00c +#define FGPI_REC_SIZE 0x010 +#define FGPI_STRIDE 0x014 +#define FGPI_NUM_RECORD_1 0x018 +#define FGPI_NUM_RECORD_2 0x01c +#define FGPI_THRESHOLD_1 0x020 +#define FGPI_THRESHOLD_2 0x024 +#define FGPI_D1_XY_START 0x028 +#define FGPI_D1_XY_END 0x02c + +#define INT_STATUS 0xfe0 +#define FGPI_BUF1_ACTIVE (0x00000001 << 7) +#define FGPI_OVERFLOW (0x00000001 << 6) +#define FGPI_MBE (0x00000001 << 5) +#define FGPI_UNDERRUN (0x00000001 << 4) +#define FGPI_THRESH2_REACHED (0x00000001 << 3) +#define FGPI_THRESH1_REACHED (0x00000001 << 2) +#define FGPI_BUF2_FULL (0x00000001 << 1) +#define FGPI_BUF1_FULL (0x00000001 << 0) + +#define INT_ENABLE 0xfe4 +#define FGPI_OVERFLOW_ENA (0x00000001 << 6) +#define FGPI_MBE_ENA (0x00000001 << 5) +#define FGPI_UNDERRUN_ENA (0x00000001 << 4) +#define FGPI_THRESH2_REACHED_ENA (0x00000001 << 3) +#define FGPI_THRESH1_REACHED_ENA (0x00000001 << 2) +#define FGPI_BUF2_FULL_ENA (0x00000001 << 1) +#define FGPI_BUF1_FULL_ENA (0x00000001 << 0) + +#define INT_CLR_STATUS 0xfe8 +#define FGPI_OVERFLOW_ACK (0x00000001 << 6) +#define FGPI_MBE_ACK (0x00000001 << 5) +#define FGPI_UNDERRUN_ACK (0x00000001 << 4) +#define FGPI_THRESH2_REACHED_ACK (0x00000001 << 3) +#define FGPI_THRESH1_REACHED_ACK (0x00000001 << 2) +#define FGPI_BUF2_DONE_ACK (0x00000001 << 1) +#define FGPI_BUF1_DONE_ACK (0x00000001 << 0) + +#define INT_SET_STATUS 0xfec +#define FGPI_OVERFLOW_SET (0x00000001 << 6) +#define FGPI_MBE_SET (0x00000001 << 5) +#define FGPI_UNDERRUN_SET (0x00000001 << 4) +#define FGPI_THRESH2_REACHED_SET (0x00000001 << 3) +#define FGPI_THRESH1_REACHED_SET (0x00000001 << 2) +#define FGPI_BUF2_DONE_SET (0x00000001 << 1) +#define FGPI_BUF1_DONE_SET (0x00000001 << 0) + +#define FGPI_SOFT_RESET 0xff0 +#define FGPI_SOFTWARE_RESET (0x00000001 << 0) + +#define FGPI_INTERFACE 0xff4 +#define FGPI_DISABLE_BUS_IF (0x00000001 << 0) + +#define FGPI_MOD_ID_EXT 0xff8 +#define FGPI_MODULE_ID 0xffc + + +/* -------------- AI Registers ---------------- */ + +#define AI0 0x00006000 +#define AI1 0x00007000 + +#define AI_STATUS 0x000 +#define AI_BUF1_ACTIVE (0x00000001 << 4) +#define AI_OVERRUN (0x00000001 << 3) +#define AI_HBE (0x00000001 << 2) +#define AI_BUF2_FULL (0x00000001 << 1) +#define AI_BUF1_FULL (0x00000001 << 0) + +#define AI_CTL 0x004 +#define AI_RESET (0x00000001 << 31) +#define AI_CAP_ENABLE (0x00000001 << 30) +#define AI_CAP_MODE (0x00000003 << 28) +#define AI_SIGN_CONVERT (0x00000001 << 27) +#define AI_EARLYMODE (0x00000001 << 26) +#define AI_DIAGMODE (0x00000001 << 25) +#define AI_RAWMODE (0x00000001 << 24) +#define AI_OVR_INTEN (0x00000001 << 7) +#define AI_HBE_INTEN (0x00000001 << 6) +#define AI_BUF2_INTEN (0x00000001 << 5) +#define AI_BUF1_INTEN (0x00000001 << 4) +#define AI_ACK_OVR (0x00000001 << 3) +#define AI_ACK_HBE (0x00000001 << 2) +#define AI_ACK2 (0x00000001 << 1) +#define AI_ACK1 (0x00000001 << 0) + +#define AI_SERIAL 0x008 +#define AI_SER_MASTER (0x00000001 << 31) +#define AI_DATAMODE (0x00000001 << 30) +#define AI_FRAMEMODE (0x00000003 << 28) +#define AI_CLOCK_EDGE (0x00000001 << 27) +#define AI_SSPOS4 (0x00000001 << 19) +#define AI_NR_CHAN (0x00000003 << 17) +#define AI_WSDIV (0x000001ff << 8) +#define AI_SCKDIV (0x000000ff << 0) + +#define AI_FRAMING 0x00c +#define AI_VALIDPOS (0x000001ff << 22) +#define AI_LEFTPOS (0x000001ff << 13) +#define AI_RIGHTPOS (0x000001ff << 4) +#define AI_SSPOS_3_0 (0x0000000f << 0) + +#define AI_BASE1 0x014 +#define AI_BASE2 0x018 +#define AI_BASE (0x03ffffff << 6) + +#define AI_SIZE 0x01c +#define AI_SAMPLE_SIZE (0x03ffffff << 6) + +#define AI_INT_ACK 0x020 +#define AI_ACK_OVR (0x00000001 << 3) +#define AI_ACK_HBE (0x00000001 << 2) +#define AI_ACK2 (0x00000001 << 1) +#define AI_ACK1 (0x00000001 << 0) + +#define AI_PWR_DOWN 0xff4 +#define AI_PWR_DWN (0x00000001 << 0) + +/* -------------- BAM Registers -------------- */ + +#define BAM 0x00008000 + +#define BAM_VI0_0_DMA_BUF_MODE 0x000 + +#define BAM_VI0_0_ADDR_OFFST_0 0x004 +#define BAM_VI0_0_ADDR_OFFST_1 0x008 +#define BAM_VI0_0_ADDR_OFFST_2 0x00c +#define BAM_VI0_0_ADDR_OFFST_3 0x010 +#define BAM_VI0_0_ADDR_OFFST_4 0x014 +#define BAM_VI0_0_ADDR_OFFST_5 0x018 +#define BAM_VI0_0_ADDR_OFFST_6 0x01c +#define BAM_VI0_0_ADDR_OFFST_7 0x020 + +#define BAM_VI0_1_DMA_BUF_MODE 0x024 +#define BAM_VI0_1_ADDR_OFFST_0 0x028 +#define BAM_VI0_1_ADDR_OFFST_1 0x02c +#define BAM_VI0_1_ADDR_OFFST_2 0x030 +#define BAM_VI0_1_ADDR_OFFST_3 0x034 +#define BAM_VI0_1_ADDR_OFFST_4 0x038 +#define BAM_VI0_1_ADDR_OFFST_5 0x03c +#define BAM_VI0_1_ADDR_OFFST_6 0x040 +#define BAM_VI0_1_ADDR_OFFST_7 0x044 + +#define BAM_VI0_2_DMA_BUF_MODE 0x048 +#define BAM_VI0_2_ADDR_OFFST_0 0x04c +#define BAM_VI0_2_ADDR_OFFST_1 0x050 +#define BAM_VI0_2_ADDR_OFFST_2 0x054 +#define BAM_VI0_2_ADDR_OFFST_3 0x058 +#define BAM_VI0_2_ADDR_OFFST_4 0x05c +#define BAM_VI0_2_ADDR_OFFST_5 0x060 +#define BAM_VI0_2_ADDR_OFFST_6 0x064 +#define BAM_VI0_2_ADDR_OFFST_7 0x068 + + +#define BAM_VI1_0_DMA_BUF_MODE 0x06c +#define BAM_VI1_0_ADDR_OFFST_0 0x070 +#define BAM_VI1_0_ADDR_OFFST_1 0x074 +#define BAM_VI1_0_ADDR_OFFST_2 0x078 +#define BAM_VI1_0_ADDR_OFFST_3 0x07c +#define BAM_VI1_0_ADDR_OFFST_4 0x080 +#define BAM_VI1_0_ADDR_OFFST_5 0x084 +#define BAM_VI1_0_ADDR_OFFST_6 0x088 +#define BAM_VI1_0_ADDR_OFFST_7 0x08c + +#define BAM_VI1_1_DMA_BUF_MODE 0x090 +#define BAM_VI1_1_ADDR_OFFST_0 0x094 +#define BAM_VI1_1_ADDR_OFFST_1 0x098 +#define BAM_VI1_1_ADDR_OFFST_2 0x09c +#define BAM_VI1_1_ADDR_OFFST_3 0x0a0 +#define BAM_VI1_1_ADDR_OFFST_4 0x0a4 +#define BAM_VI1_1_ADDR_OFFST_5 0x0a8 +#define BAM_VI1_1_ADDR_OFFST_6 0x0ac +#define BAM_VI1_1_ADDR_OFFST_7 0x0b0 + +#define BAM_VI1_2_DMA_BUF_MODE 0x0b4 +#define BAM_VI1_2_ADDR_OFFST_0 0x0b8 +#define BAM_VI1_2_ADDR_OFFST_1 0x0bc +#define BAM_VI1_2_ADDR_OFFST_2 0x0c0 +#define BAM_VI1_2_ADDR_OFFST_3 0x0c4 +#define BAM_VI1_2_ADDR_OFFST_4 0x0c8 +#define BAM_VI1_2_ADDR_OFFST_5 0x0cc +#define BAM_VI1_2_ADDR_OFFST_6 0x0d0 +#define BAM_VI1_2_ADDR_OFFST_7 0x0d4 + + +#define BAM_FGPI0_DMA_BUF_MODE 0x0d8 +#define BAM_FGPI0_ADDR_OFFST_0 0x0dc +#define BAM_FGPI0_ADDR_OFFST_1 0x0e0 +#define BAM_FGPI0_ADDR_OFFST_2 0x0e4 +#define BAM_FGPI0_ADDR_OFFST_3 0x0e8 +#define BAM_FGPI0_ADDR_OFFST_4 0x0ec +#define BAM_FGPI0_ADDR_OFFST_5 0x0f0 +#define BAM_FGPI0_ADDR_OFFST_6 0x0f4 +#define BAM_FGPI0_ADDR_OFFST_7 0x0f8 + +#define BAM_FGPI1_DMA_BUF_MODE 0x0fc +#define BAM_FGPI1_ADDR_OFFST_0 0x100 +#define BAM_FGPI1_ADDR_OFFST_1 0x104 +#define BAM_FGPI1_ADDR_OFFST_2 0x108 +#define BAM_FGPI1_ADDR_OFFST_3 0x10c +#define BAM_FGPI1_ADDR_OFFST_4 0x110 +#define BAM_FGPI1_ADDR_OFFST_5 0x114 +#define BAM_FGPI1_ADDR_OFFST_6 0x118 +#define BAM_FGPI1_ADDR_OFFST_7 0x11c + +#define BAM_FGPI2_DMA_BUF_MODE 0x120 +#define BAM_FGPI2_ADDR_OFFST_0 0x124 +#define BAM_FGPI2_ADDR_OFFST_1 0x128 +#define BAM_FGPI2_ADDR_OFFST_2 0x12c +#define BAM_FGPI2_ADDR_OFFST_3 0x130 +#define BAM_FGPI2_ADDR_OFFST_4 0x134 +#define BAM_FGPI2_ADDR_OFFST_5 0x138 +#define BAM_FGPI2_ADDR_OFFST_6 0x13c +#define BAM_FGPI2_ADDR_OFFST_7 0x140 + +#define BAM_FGPI3_DMA_BUF_MODE 0x144 +#define BAM_FGPI3_ADDR_OFFST_0 0x148 +#define BAM_FGPI3_ADDR_OFFST_1 0x14c +#define BAM_FGPI3_ADDR_OFFST_2 0x150 +#define BAM_FGPI3_ADDR_OFFST_3 0x154 +#define BAM_FGPI3_ADDR_OFFST_4 0x158 +#define BAM_FGPI3_ADDR_OFFST_5 0x15c +#define BAM_FGPI3_ADDR_OFFST_6 0x160 +#define BAM_FGPI3_ADDR_OFFST_7 0x164 + + +#define BAM_AI0_DMA_BUF_MODE 0x168 +#define BAM_AI0_ADDR_OFFST_0 0x16c +#define BAM_AI0_ADDR_OFFST_1 0x170 +#define BAM_AI0_ADDR_OFFST_2 0x174 +#define BAM_AI0_ADDR_OFFST_3 0x178 +#define BAM_AI0_ADDR_OFFST_4 0x17c +#define BAM_AIO_ADDR_OFFST_5 0x180 +#define BAM_AI0_ADDR_OFFST_6 0x184 +#define BAM_AIO_ADDR_OFFST_7 0x188 + +#define BAM_AI1_DMA_BUF_MODE 0x18c +#define BAM_AI1_ADDR_OFFST_0 0x190 +#define BAM_AI1_ADDR_OFFST_1 0x194 +#define BAM_AI1_ADDR_OFFST_2 0x198 +#define BAM_AI1_ADDR_OFFST_3 0x19c +#define BAM_AI1_ADDR_OFFST_4 0x1a0 +#define BAM_AI1_ADDR_OFFST_5 0x1a4 +#define BAM_AI1_ADDR_OFFST_6 0x1a8 +#define BAM_AI1_ADDR_OFFST_7 0x1ac + +#define BAM_SW_RST 0xff0 +#define BAM_SW_RESET (0x00000001 << 0) + + + + + +/* -------------- MMU Registers -------------- */ + +#define MMU 0x00009000 + +#define MMU_MODE 0x000 + +#define MMU_DMA_CONFIG0 0x004 +#define MMU_DMA_CONFIG1 0x008 +#define MMU_DMA_CONFIG2 0x00c +#define MMU_DMA_CONFIG3 0x010 +#define MMU_DMA_CONFIG4 0x014 +#define MMU_DMA_CONFIG5 0x018 +#define MMU_DMA_CONFIG6 0x01c +#define MMU_DMA_CONFIG7 0x020 +#define MMU_DMA_CONFIG8 0x024 +#define MMU_DMA_CONFIG9 0x028 +#define MMU_DMA_CONFIG10 0x02c +#define MMU_DMA_CONFIG11 0x030 +#define MMU_DMA_CONFIG12 0x034 +#define MMU_DMA_CONFIG13 0x038 +#define MMU_DMA_CONFIG14 0x03c +#define MMU_DMA_CONFIG15 0x040 + +#define MMU_SW_RST 0xff0 +#define MMU_SW_RESET (0x0001 << 0) + +#define MMU_PTA_BASE0 0x044 /* DMA 0 */ +#define MMU_PTA_BASE1 0x084 /* DMA 1 */ +#define MMU_PTA_BASE2 0x0c4 /* DMA 2 */ +#define MMU_PTA_BASE3 0x104 /* DMA 3 */ +#define MMU_PTA_BASE4 0x144 /* DMA 4 */ +#define MMU_PTA_BASE5 0x184 /* DMA 5 */ +#define MMU_PTA_BASE6 0x1c4 /* DMA 6 */ +#define MMU_PTA_BASE7 0x204 /* DMA 7 */ +#define MMU_PTA_BASE8 0x244 /* DMA 8 */ +#define MMU_PTA_BASE9 0x284 /* DMA 9 */ +#define MMU_PTA_BASE10 0x2c4 /* DMA 10 */ +#define MMU_PTA_BASE11 0x304 /* DMA 11 */ +#define MMU_PTA_BASE12 0x344 /* DMA 12 */ +#define MMU_PTA_BASE13 0x384 /* DMA 13 */ +#define MMU_PTA_BASE14 0x3c4 /* DMA 14 */ +#define MMU_PTA_BASE15 0x404 /* DMA 15 */ + +#define MMU_PTA_BASE 0x044 /* DMA 0 */ +#define MMU_PTA_OFFSET 0x40 + +#define PTA_BASE(__ch) (MMU_PTA_BASE + (MMU_PTA_OFFSET * __ch)) + +#define MMU_PTA0_LSB(__ch) PTA_BASE(__ch) + 0x00 +#define MMU_PTA0_MSB(__ch) PTA_BASE(__ch) + 0x04 +#define MMU_PTA1_LSB(__ch) PTA_BASE(__ch) + 0x08 +#define MMU_PTA1_MSB(__ch) PTA_BASE(__ch) + 0x0c +#define MMU_PTA2_LSB(__ch) PTA_BASE(__ch) + 0x10 +#define MMU_PTA2_MSB(__ch) PTA_BASE(__ch) + 0x14 +#define MMU_PTA3_LSB(__ch) PTA_BASE(__ch) + 0x18 +#define MMU_PTA3_MSB(__ch) PTA_BASE(__ch) + 0x1c +#define MMU_PTA4_LSB(__ch) PTA_BASE(__ch) + 0x20 +#define MMU_PTA4_MSB(__ch) PTA_BASE(__ch) + 0x24 +#define MMU_PTA5_LSB(__ch) PTA_BASE(__ch) + 0x28 +#define MMU_PTA5_MSB(__ch) PTA_BASE(__ch) + 0x2c +#define MMU_PTA6_LSB(__ch) PTA_BASE(__ch) + 0x30 +#define MMU_PTA6_MSB(__ch) PTA_BASE(__ch) + 0x34 +#define MMU_PTA7_LSB(__ch) PTA_BASE(__ch) + 0x38 +#define MMU_PTA7_MSB(__ch) PTA_BASE(__ch) + 0x3c + + +/* -------------- MSI Registers -------------- */ + +#define MSI 0x0000a000 + +#define MSI_DELAY_TIMER 0x000 +#define MSI_DELAY_1CLK (0x00000001 << 0) +#define MSI_DELAY_2CLK (0x00000002 << 0) + +#define MSI_INTA_POLARITY 0x004 +#define MSI_INTA_POLARITY_HIGH (0x00000001 << 0) + +#define MSI_CONFIG0 0x008 +#define MSI_CONFIG1 0x00c +#define MSI_CONFIG2 0x010 +#define MSI_CONFIG3 0x014 +#define MSI_CONFIG4 0x018 +#define MSI_CONFIG5 0x01c +#define MSI_CONFIG6 0x020 +#define MSI_CONFIG7 0x024 +#define MSI_CONFIG8 0x028 +#define MSI_CONFIG9 0x02c +#define MSI_CONFIG10 0x030 +#define MSI_CONFIG11 0x034 +#define MSI_CONFIG12 0x038 +#define MSI_CONFIG13 0x03c +#define MSI_CONFIG14 0x040 +#define MSI_CONFIG15 0x044 +#define MSI_CONFIG16 0x048 +#define MSI_CONFIG17 0x04c +#define MSI_CONFIG18 0x050 +#define MSI_CONFIG19 0x054 +#define MSI_CONFIG20 0x058 +#define MSI_CONFIG21 0x05c +#define MSI_CONFIG22 0x060 +#define MSI_CONFIG23 0x064 +#define MSI_CONFIG24 0x068 +#define MSI_CONFIG25 0x06c +#define MSI_CONFIG26 0x070 +#define MSI_CONFIG27 0x074 +#define MSI_CONFIG28 0x078 +#define MSI_CONFIG29 0x07c +#define MSI_CONFIG30 0x080 +#define MSI_CONFIG31 0x084 +#define MSI_CONFIG32 0x088 +#define MSI_CONFIG33 0x08c +#define MSI_CONFIG34 0x090 +#define MSI_CONFIG35 0x094 +#define MSI_CONFIG36 0x098 +#define MSI_CONFIG37 0x09c +#define MSI_CONFIG38 0x0a0 +#define MSI_CONFIG39 0x0a4 +#define MSI_CONFIG40 0x0a8 +#define MSI_CONFIG41 0x0ac +#define MSI_CONFIG42 0x0b0 +#define MSI_CONFIG43 0x0b4 +#define MSI_CONFIG44 0x0b8 +#define MSI_CONFIG45 0x0bc +#define MSI_CONFIG46 0x0c0 +#define MSI_CONFIG47 0x0c4 +#define MSI_CONFIG48 0x0c8 +#define MSI_CONFIG49 0x0cc +#define MSI_CONFIG50 0x0d0 + +#define MSI_INT_POL_EDGE_RISE (0x00000001 << 24) +#define MSI_INT_POL_EDGE_FALL (0x00000002 << 24) +#define MSI_INT_POL_EDGE_ANY (0x00000003 << 24) +#define MSI_TC (0x00000007 << 16) +#define MSI_ID (0x0000000f << 0) + +#define MSI_INT_STATUS_L 0xfc0 +#define MSI_INT_TAGACK_VI0_0 (0x00000001 << 0) +#define MSI_INT_TAGACK_VI0_1 (0x00000001 << 1) +#define MSI_INT_TAGACK_VI0_2 (0x00000001 << 2) +#define MSI_INT_TAGACK_VI1_0 (0x00000001 << 3) +#define MSI_INT_TAGACK_VI1_1 (0x00000001 << 4) +#define MSI_INT_TAGACK_VI1_2 (0x00000001 << 5) +#define MSI_INT_TAGACK_FGPI_0 (0x00000001 << 6) +#define MSI_INT_TAGACK_FGPI_1 (0x00000001 << 7) +#define MSI_INT_TAGACK_FGPI_2 (0x00000001 << 8) +#define MSI_INT_TAGACK_FGPI_3 (0x00000001 << 9) +#define MSI_INT_TAGACK_AI_0 (0x00000001 << 10) +#define MSI_INT_TAGACK_AI_1 (0x00000001 << 11) +#define MSI_INT_OVRFLW_VI0_0 (0x00000001 << 12) +#define MSI_INT_OVRFLW_VI0_1 (0x00000001 << 13) +#define MSI_INT_OVRFLW_VI0_2 (0x00000001 << 14) +#define MSI_INT_OVRFLW_VI1_0 (0x00000001 << 15) +#define MSI_INT_OVRFLW_VI1_1 (0x00000001 << 16) +#define MSI_INT_OVRFLW_VI1_2 (0x00000001 << 17) +#define MSI_INT_OVRFLW_FGPI_O (0x00000001 << 18) +#define MSI_INT_OVRFLW_FGPI_1 (0x00000001 << 19) +#define MSI_INT_OVRFLW_FGPI_2 (0x00000001 << 20) +#define MSI_INT_OVRFLW_FGPI_3 (0x00000001 << 21) +#define MSI_INT_OVRFLW_AI_0 (0x00000001 << 22) +#define MSI_INT_OVRFLW_AI_1 (0x00000001 << 23) +#define MSI_INT_AVINT_VI0 (0x00000001 << 24) +#define MSI_INT_AVINT_VI1 (0x00000001 << 25) +#define MSI_INT_AVINT_FGPI_0 (0x00000001 << 26) +#define MSI_INT_AVINT_FGPI_1 (0x00000001 << 27) +#define MSI_INT_AVINT_FGPI_2 (0x00000001 << 28) +#define MSI_INT_AVINT_FGPI_3 (0x00000001 << 29) +#define MSI_INT_AVINT_AI_0 (0x00000001 << 30) +#define MSI_INT_AVINT_AI_1 (0x00000001 << 31) + +#define MSI_INT_STATUS_H 0xfc4 +#define MSI_INT_UNMAPD_TC_INT (0x00000001 << 0) +#define MSI_INT_EXTINT_0 (0x00000001 << 1) +#define MSI_INT_EXTINT_1 (0x00000001 << 2) +#define MSI_INT_EXTINT_2 (0x00000001 << 3) +#define MSI_INT_EXTINT_3 (0x00000001 << 4) +#define MSI_INT_EXTINT_4 (0x00000001 << 5) +#define MSI_INT_EXTINT_5 (0x00000001 << 6) +#define MSI_INT_EXTINT_6 (0x00000001 << 7) +#define MSI_INT_EXTINT_7 (0x00000001 << 8) +#define MSI_INT_EXTINT_8 (0x00000001 << 9) +#define MSI_INT_EXTINT_9 (0x00000001 << 10) +#define MSI_INT_EXTINT_10 (0x00000001 << 11) +#define MSI_INT_EXTINT_11 (0x00000001 << 12) +#define MSI_INT_EXTINT_12 (0x00000001 << 13) +#define MSI_INT_EXTINT_13 (0x00000001 << 14) +#define MSI_INT_EXTINT_14 (0x00000001 << 15) +#define MSI_INT_EXTINT_15 (0x00000001 << 16) +#define MSI_INT_I2CINT_0 (0x00000001 << 17) +#define MSI_INT_I2CINT_1 (0x00000001 << 18) + +#define MSI_INT_STATUS_CLR_L 0xfc8 +#define MSI_INT_STATUS_CLR_H 0xfcc +#define MSI_INT_STATUS_SET_L 0xfd0 +#define MSI_INT_STATUS_SET_H 0xfd4 +#define MSI_INT_ENA_L 0xfd8 +#define MSI_INT_ENA_H 0xfdc +#define MSI_INT_ENA_CLR_L 0xfe0 +#define MSI_INT_ENA_CLR_H 0xfe4 +#define MSI_INT_ENA_SET_L 0xfe8 +#define MSI_INT_ENA_SET_H 0xfec + +#define MSI_SW_RST 0xff0 +#define MSI_SW_RESET (0x0001 << 0) + +#define MSI_MODULE_ID 0xffc + + +/* -------------- I2C Registers -------------- */ + +#define I2C_B 0x0000b000 +#define I2C_A 0x0000c000 + +#define RX_FIFO 0x000 +#define I2C_RX_BYTE (0x000000ff << 0) + +#define TX_FIFO 0x000 +#define I2C_STOP_BIT (0x00000001 << 9) +#define I2C_START_BIT (0x00000001 << 8) +#define I2C_TX_BYTE (0x000000ff << 0) + +#define I2C_STATUS 0x008 +#define I2C_TRANSMIT (0x00000001 << 11) +#define I2C_RECEIVE (0x00000001 << 10) +#define I2C_TRANSMIT_S_PROG (0x00000001 << 9) +#define I2C_TRANSMIT_S_CLEAR (0x00000001 << 8) +#define I2C_TRANSMIT_PROG (0x00000001 << 7) +#define I2C_TRANSMIT_CLEAR (0x00000001 << 6) +#define I2C_RECEIVE_PROG (0x00000001 << 5) +#define I2C_RECEIVE_CLEAR (0x00000001 << 4) +#define I2C_SDA_LINE (0x00000001 << 3) +#define I2C_SCL_LINE (0x00000001 << 2) +#define I2C_START_STOP_FLAG (0x00000001 << 1) +#define I2C_MODE_STATUS (0x00000001 << 0) + +#define I2C_CONTROL 0x00c +#define I2C_SCL_CONTROL (0x00000001 << 7) +#define I2C_SDA_CONTROL (0x00000001 << 6) +#define I2C_RECEIVE_PROTECT (0x00000001 << 5) +#define I2C_RECEIVE_PRO_READ (0x00000001 << 4) +#define I2C_TRANS_SELF_CLEAR (0x00000001 << 3) +#define I2C_TRANS_S_SELF_CLEAR (0x00000001 << 2) +#define I2C_SLAVE_ADDR_10BIT (0x00000001 << 1) +#define I2C_RESET (0x00000001 << 0) + +#define I2C_CLOCK_DIVISOR_HIGH 0x010 +#define I2C_CLOCK_HIGH (0x0000ffff << 0) + +#define I2C_CLOCK_DIVISOR_LOW 0x014 +#define I2C_CLOCK_LOW (0x0000ffff << 0) + +#define I2C_RX_LEVEL 0x01c +#define I2C_RECEIVE_RANGE (0x0000007f << 0) + +#define I2C_TX_LEVEL 0x020 +#define I2C_TRANSMIT_RANGE (0x0000007f << 0) + +#define I2C_SDA_HOLD 0x028 +#define I2C_HOLD_TIME (0x0000007f << 0) + +#define MODULE_CONF 0xfd4 +#define INT_CLR_ENABLE 0xfd8 +#define I2C_CLR_ENABLE_STFNF (0x00000001 << 12) +#define I2C_CLR_ENABLE_MTFNF (0x00000001 << 11) +#define I2C_CLR_ENABLE_RFDA (0x00000001 << 10) +#define I2C_CLR_ENABLE_RFF (0x00000001 << 9) +#define I2C_CLR_ENABLE_STDR (0x00000001 << 8) +#define I2C_CLR_ENABLE_MTDR (0x00000001 << 7) +#define I2C_CLR_ENABLE_IBE (0x00000001 << 6) +#define I2C_CLR_ENABLE_MSMC (0x00000001 << 5) +#define I2C_CLR_ENABLE_SRSD (0x00000001 << 4) +#define I2C_CLR_ENABLE_STSD (0x00000001 << 3) +#define I2C_CLR_ENABLE_MTNA (0x00000001 << 2) +#define I2C_CLR_ENABLE_MAF (0x00000001 << 1) +#define I2C_CLR_ENABLE_MTD (0x00000001 << 0) + +#define INT_SET_ENABLE 0xfdc +#define I2C_SET_ENABLE_STFNF (0x00000001 << 12) +#define I2C_SET_ENABLE_MTFNF (0x00000001 << 11) +#define I2C_SET_ENABLE_RFDA (0x00000001 << 10) +#define I2C_SET_ENABLE_RFF (0x00000001 << 9) +#define I2C_SET_ENABLE_STDR (0x00000001 << 8) +#define I2C_SET_ENABLE_MTDR (0x00000001 << 7) +#define I2C_SET_ENABLE_IBE (0x00000001 << 6) +#define I2C_SET_ENABLE_MSMC (0x00000001 << 5) +#define I2C_SET_ENABLE_SRSD (0x00000001 << 4) +#define I2C_SET_ENABLE_STSD (0x00000001 << 3) +#define I2C_SET_ENABLE_MTNA (0x00000001 << 2) +#define I2C_SET_ENABLE_MAF (0x00000001 << 1) +#define I2C_SET_ENABLE_MTD (0x00000001 << 0) + +#define INT_STATUS 0xfe0 +#define I2C_INTERRUPT_STFNF (0x00000001 << 12) +#define I2C_INTERRUPT_MTFNF (0x00000001 << 11) +#define I2C_INTERRUPT_RFDA (0x00000001 << 10) +#define I2C_INTERRUPTE_RFF (0x00000001 << 9) +#define I2C_SLAVE_INTERRUPT_STDR (0x00000001 << 8) +#define I2C_MASTER_INTERRUPT_MTDR (0x00000001 << 7) +#define I2C_ERROR_IBE (0x00000001 << 6) +#define I2C_MODE_CHANGE_INTER_MSMC (0x00000001 << 5) +#define I2C_SLAVE_RECEIVE_INTER_SRSD (0x00000001 << 4) +#define I2C_SLAVE_TRANSMIT_INTER_STSD (0x00000001 << 3) +#define I2C_ACK_INTER_MTNA (0x00000001 << 2) +#define I2C_FAILURE_INTER_MAF (0x00000001 << 1) +#define I2C_INTERRUPT_MTD (0x00000001 << 0) + +#define INT_ENABLE 0xfe4 +#define I2C_ENABLE_STFNF (0x00000001 << 12) +#define I2C_ENABLE_MTFNF (0x00000001 << 11) +#define I2C_ENABLE_RFDA (0x00000001 << 10) +#define I2C_ENABLE_RFF (0x00000001 << 9) +#define I2C_ENABLE_STDR (0x00000001 << 8) +#define I2C_ENABLE_MTDR (0x00000001 << 7) +#define I2C_ENABLE_IBE (0x00000001 << 6) +#define I2C_ENABLE_MSMC (0x00000001 << 5) +#define I2C_ENABLE_SRSD (0x00000001 << 4) +#define I2C_ENABLE_STSD (0x00000001 << 3) +#define I2C_ENABLE_MTNA (0x00000001 << 2) +#define I2C_ENABLE_MAF (0x00000001 << 1) +#define I2C_ENABLE_MTD (0x00000001 << 0) + +#define INT_CLR_STATUS 0xfe8 +#define I2C_CLR_STATUS_STFNF (0x00000001 << 12) +#define I2C_CLR_STATUS_MTFNF (0x00000001 << 11) +#define I2C_CLR_STATUS_RFDA (0x00000001 << 10) +#define I2C_CLR_STATUS_RFF (0x00000001 << 9) +#define I2C_CLR_STATUS_STDR (0x00000001 << 8) +#define I2C_CLR_STATUS_MTDR (0x00000001 << 7) +#define I2C_CLR_STATUS_IBE (0x00000001 << 6) +#define I2C_CLR_STATUS_MSMC (0x00000001 << 5) +#define I2C_CLR_STATUS_SRSD (0x00000001 << 4) +#define I2C_CLR_STATUS_STSD (0x00000001 << 3) +#define I2C_CLR_STATUS_MTNA (0x00000001 << 2) +#define I2C_CLR_STATUS_MAF (0x00000001 << 1) +#define I2C_CLR_STATIS_MTD (0x00000001 << 0) + +#define INT_SET_STATUS 0xfec +#define I2C_SET_STATUS_STFNF (0x00000001 << 12) +#define I2C_SET_STATUS_MTFNF (0x00000001 << 11) +#define I2C_SET_STATUS_RFDA (0x00000001 << 10) +#define I2C_SET_STATUS_RFF (0x00000001 << 9) +#define I2C_SET_STATUS_STDR (0x00000001 << 8) +#define I2C_SET_STATUS_MTDR (0x00000001 << 7) +#define I2C_SET_STATUS_IBE (0x00000001 << 6) +#define I2C_SET_STATUS_MSMC (0x00000001 << 5) +#define I2C_SET_STATUS_SRSD (0x00000001 << 4) +#define I2C_SET_STATUS_STSD (0x00000001 << 3) +#define I2C_SET_STATUS_MTNA (0x00000001 << 2) +#define I2C_SET_STATUS_MAF (0x00000001 << 1) +#define I2C_SET_STATIS_MTD (0x00000001 << 0) + + + + +/* -------------- SPI Registers -------------- */ + +#define SPI 0x0000d000 + +#define SPI_CONTROL_REG 0x000 +#define SPI_SERIAL_INTER_ENABLE (0x00000001 << 7) +#define SPI_LSB_FIRST_ENABLE (0x00000001 << 6) +#define SPI_MODE_SELECT (0x00000001 << 5) +#define SPI_CLOCK_POLARITY (0x00000001 << 4) +#define SPI_CLOCK_PHASE (0x00000001 << 3) + +#define SPI_STATUS 0x004 +#define SPI_TRANSFER_FLAG (0x00000001 << 7) +#define SPI_WRITE_COLLISSION (0x00000001 << 6) +#define SPI_READ_OVERRUN (0x00000001 << 5) +#define SPI_MODE_FAULT (0x00000001 << 4) +#define SPI_SLAVE_ABORT (0x00000001 << 3) + +#define SPI_DATA 0x008 +#define SPI_BIDI_DATA (0x000000ff << 0) + +#define SPI_CLOCK_COUNTER 0x00c +#define SPI_CLOCK (0x00000001 << 0) + + + + +/* -------------- GPIO Registers -------------- */ + +#define GPIO 0x0000e000 + +#define GPIO_RD 0x000 +#define GPIO_WR 0x004 +#define GPIO_WR_MODE 0x008 +#define GPIO_OEN 0x00c + +#define GPIO_SW_RST 0xff0 +#define GPIO_SW_RESET (0x00000001 << 0) + +#define GPIO_31 (1 << 31) +#define GPIO_30 (1 << 30) +#define GPIO_29 (1 << 29) +#define GPIO_28 (1 << 28) +#define GPIO_27 (1 << 27) +#define GPIO_26 (1 << 26) +#define GPIO_25 (1 << 25) +#define GPIO_24 (1 << 24) +#define GPIO_23 (1 << 23) +#define GPIO_22 (1 << 22) +#define GPIO_21 (1 << 21) +#define GPIO_20 (1 << 20) +#define GPIO_19 (1 << 19) +#define GPIO_18 (1 << 18) +#define GPIO_17 (1 << 17) +#define GPIO_16 (1 << 16) +#define GPIO_15 (1 << 15) +#define GPIO_14 (1 << 14) +#define GPIO_13 (1 << 13) +#define GPIO_12 (1 << 12) +#define GPIO_11 (1 << 11) +#define GPIO_10 (1 << 10) +#define GPIO_09 (1 << 9) +#define GPIO_08 (1 << 8) +#define GPIO_07 (1 << 7) +#define GPIO_06 (1 << 6) +#define GPIO_05 (1 << 5) +#define GPIO_04 (1 << 4) +#define GPIO_03 (1 << 3) +#define GPIO_02 (1 << 2) +#define GPIO_01 (1 << 1) +#define GPIO_00 (1 << 0) + +/* -------------- PHI_0 Registers -------------- */ + +#define PHI_0 0x0000f000 + +#define PHI_0_MODE 0x0000 +#define PHI_0_0_CONFIG 0x0008 +#define PHI_0_1_CONFIG 0x000c +#define PHI_0_2_CONFIG 0x0010 +#define PHI_0_3_CONFIG 0x0014 + +#define PHI_POLARITY 0x0038 +#define PHI_TIMEOUT 0x003c +#define PHI_SW_RST 0x0ff0 + +#define PHI_0_0_RW_0 0x1000 +#define PHI_0_0_RW_511 0x17fc + +#define PHI_0_1_RW_0 0x1800 +#define PHI_0_1_RW_511 0x1ffc + +#define PHI_0_2_RW_0 0x2000 +#define PHI_0_2_RW_511 0x27fc + +#define PHI_0_3_RW_0 0x2800 +#define PHI_0_3_RW_511 0x2ffc + +#define PHI_CSN_DEASSERT (0x00000001 << 2) +#define PHI_AUTO_INCREMENT (0x00000001 << 1) +#define PHI_FIFO_MODE (0x00000001 << 0) + +#define PHI_DELAY_RD_WR (0x0000001f << 27) +#define PHI_EXTEND_RDY3 (0x00000003 << 25) +#define PHI_EXTEND_RDY2 (0x00000003 << 23) +#define PHI_EXTEND_RDY1 (0x00000003 << 21) +#define PHI_EXTEND_RDY0 (0x00000003 << 19) +#define PHI_RDY3_OD (0x00000001 << 18) +#define PHI_RDY2_OD (0x00000001 << 17) +#define PHI_RDY1_OD (0x00000001 << 16) +#define PHI_RDY0_OD (0x00000001 << 15) +#define PHI_ALE_POL (0x00000001 << 14) +#define PHI_WRN_POL (0x00000001 << 13) +#define PHI_RDN_POL (0x00000001 << 12) +#define PHI_RDY3_POL (0x00000001 << 11) +#define PHI_RDY2_POL (0x00000001 << 10) +#define PHI_RDY1_POL (0x00000001 << 9) +#define PHI_RDY0_POL (0x00000001 << 8) +#define PHI_CSN7_POL (0x00000001 << 7) +#define PHI_CSN6_POL (0x00000001 << 6) +#define PHI_CSN5_POL (0x00000001 << 5) +#define PHI_CSN4_POL (0x00000001 << 4) +#define PHI_CSN3_POL (0x00000001 << 3) +#define PHI_CSN2_POL (0x00000001 << 2) +#define PHI_CSN1_POL (0x00000001 << 1) +#define PHI_CSN0_POL (0x00000001 << 0) + +/* -------------- PHI_1 Registers -------------- */ + +#define PHI_1 0x00020000 + +#define PHI_1_MODE 0x00004 +#define PHI_1_0_CONFIG 0x00018 +#define PHI_1_1_CONFIG 0x0001c +#define PHI_1_2_CONFIG 0x00020 +#define PHI_1_3_CONFIG 0x00024 +#define PHI_1_4_CONFIG 0x00028 +#define PHI_1_5_CONFIG 0x0002c +#define PHI_1_6_CONFIG 0x00030 +#define PHI_1_7_CONFIG 0x00034 + +#define PHI_1_0_RW_0 0x00000 +#define PHI_1_0_RW_16383 0x0fffc + +#define PHI_1_1_RW_0 0x1000 +#define PHI_1_1_RW_16383 0x1ffc + +#define PHI_1_2_RW_0 0x2000 +#define PHI_1_2_RW_16383 0x2ffc + +#define PHI_1_3_RW_0 0x3000 +#define PHI_1_3_RW_16383 0x3ffc + +#define PHI_1_4_RW_0 0x4000 +#define PHI_1_4_RW_16383 0x4ffc + +#define PHI_1_5_RW_0 0x5000 +#define PHI_1_5_RW_16383 0x5ffc + +#define PHI_1_6_RW_0 0x6000 +#define PHI_1_6_RW_16383 0x6ffc + +#define PHI_1_7_RW_0 0x7000 +#define PHI_1_7_RW_16383 0x7ffc + +/* -------------- CGU Registers -------------- */ + +#define CGU 0x00013000 + +#define CGU_SCR_0 0x000 +#define CGU_SCR_1 0x004 +#define CGU_SCR_2 0x008 +#define CGU_SCR_3 0x00c +#define CGU_SCR_4 0x010 +#define CGU_SCR_5 0x014 +#define CGU_SCR_6 0x018 +#define CGU_SCR_7 0x01c +#define CGU_SCR_8 0x020 +#define CGU_SCR_9 0x024 +#define CGU_SCR_10 0x028 +#define CGU_SCR_11 0x02c +#define CGU_SCR_12 0x030 +#define CGU_SCR_13 0x034 +#define CGU_SCR_STOP (0x00000001 << 3) +#define CGU_SCR_RESET (0x00000001 << 2) +#define CGU_SCR_ENF2 (0x00000001 << 1) +#define CGU_SCR_ENF1 (0x00000001 << 0) + +#define CGU_FS1_0 0x038 +#define CGU_FS1_1 0x03c +#define CGU_FS1_2 0x040 +#define CGU_FS1_3 0x044 +#define CGU_FS1_4 0x048 +#define CGU_FS1_5 0x04c +#define CGU_FS1_6 0x050 +#define CGU_FS1_7 0x054 +#define CGU_FS1_8 0x058 +#define CGU_FS1_9 0x05c +#define CGU_FS1_10 0x060 +#define CGU_FS1_11 0x064 +#define CGU_FS1_12 0x068 +#define CGU_FS1_13 0x06c +#define CGU_FS1_PLL (0x00000000 << 0) + + +#define CGU_FS2_0 0x070 +#define CGU_FS2_1 0x074 +#define CGU_FS2_2 0x078 +#define CGU_FS2_3 0x07c +#define CGU_FS2_4 0x080 +#define CGU_FS2_5 0x084 +#define CGU_FS2_6 0x088 +#define CGU_FS2_7 0x08c +#define CGU_FS2_8 0x090 +#define CGU_FS2_9 0x094 +#define CGU_FS2_10 0x098 +#define CGU_FS2_11 0x09c +#define CGU_FS2_12 0x0a0 +#define CGU_FS2_13 0x0a4 + +#define CGU_SSR_0 0x0a8 +#define CGU_SSR_1 0x0ac +#define CGU_SSR_2 0x0b0 +#define CGU_SSR_3 0x0b4 +#define CGU_SSR_4 0x0b8 +#define CGU_SSR_5 0x0bc +#define CGU_SSR_6 0x0c0 +#define CGU_SSR_7 0x0c4 +#define CGU_SSR_8 0x0c8 +#define CGU_SSR_9 0x0cc +#define CGU_SSR_10 0x0d0 +#define CGU_SSR_11 0x0d4 +#define CGU_SSR_12 0x0d8 +#define CGU_SSR_13 0x0dc + +#define CGU_PCR_0_0 0x0e0 +#define CGU_PCR_0_1 0x0e4 +#define CGU_PCR_0_2 0x0e8 +#define CGU_PCR_0_3 0x0ec +#define CGU_PCR_0_4 0x0f0 +#define CGU_PCR_0_5 0x0f4 +#define CGU_PCR_0_6 0x0f8 +#define CGU_PCR_0_7 0x0fc +#define CGU_PCR_1_0 0x100 +#define CGU_PCR_1_1 0x104 +#define CGU_PCR_2_0 0x108 +#define CGU_PCR_2_1 0x10c +#define CGU_PCR_3_0 0x110 +#define CGU_PCR_3_1 0x114 +#define CGU_PCR_3_2 0x118 +#define CGU_PCR_4_0 0x11c +#define CGU_PCR_4_1 0x120 +#define CGU_PCR_5 0x124 +#define CGU_PCR_6 0x128 +#define CGU_PCR_7 0x12c +#define CGU_PCR_8 0x130 +#define CGU_PCR_9 0x134 +#define CGU_PCR_10 0x138 +#define CGU_PCR_11 0x13c +#define CGU_PCR_12 0x140 +#define CGU_PCR_13 0x144 +#define CGU_PCR_WAKE_EN (0x00000001 << 2) +#define CGU_PCR_AUTO (0x00000001 << 1) +#define CGU_PCR_RUN (0x00000001 << 0) + + +#define CGU_PSR_0_0 0x148 +#define CGU_PSR_0_1 0x14c +#define CGU_PSR_0_2 0x150 +#define CGU_PSR_0_3 0x154 +#define CGU_PSR_0_4 0x158 +#define CGU_PSR_0_5 0x15c +#define CGU_PSR_0_6 0x160 +#define CGU_PSR_0_7 0x164 +#define CGU_PSR_1_0 0x168 +#define CGU_PSR_1_1 0x16c +#define CGU_PSR_2_0 0x170 +#define CGU_PSR_2_1 0x174 +#define CGU_PSR_3_0 0x178 +#define CGU_PSR_3_1 0x17c +#define CGU_PSR_3_2 0x180 +#define CGU_PSR_4_0 0x184 +#define CGU_PSR_4_1 0x188 +#define CGU_PSR_5 0x18c +#define CGU_PSR_6 0x190 +#define CGU_PSR_7 0x194 +#define CGU_PSR_8 0x198 +#define CGU_PSR_9 0x19c +#define CGU_PSR_10 0x1a0 +#define CGU_PSR_11 0x1a4 +#define CGU_PSR_12 0x1a8 +#define CGU_PSR_13 0x1ac + +#define CGU_ESR_0_0 0x1b0 +#define CGU_ESR_0_1 0x1b4 +#define CGU_ESR_0_2 0x1b8 +#define CGU_ESR_0_3 0x1bc +#define CGU_ESR_0_4 0x1c0 +#define CGU_ESR_0_5 0x1c4 +#define CGU_ESR_0_6 0x1c8 +#define CGU_ESR_0_7 0x1cc +#define CGU_ESR_1_0 0x1d0 +#define CGU_ESR_1_1 0x1d4 +#define CGU_ESR_2_0 0x1d8 +#define CGU_ESR_2_1 0x1dc +#define CGU_ESR_3_0 0x1e0 +#define CGU_ESR_3_1 0x1e4 +#define CGU_ESR_3_2 0x1e8 +#define CGU_ESR_4_0 0x1ec +#define CGU_ESR_4_1 0x1f0 +#define CGU_ESR_5 0x1f4 +#define CGU_ESR_6 0x1f8 +#define CGU_ESR_7 0x1fc +#define CGU_ESR_8 0x200 +#define CGU_ESR_9 0x204 +#define CGU_ESR_10 0x208 +#define CGU_ESR_11 0x20c +#define CGU_ESR_12 0x210 +#define CGU_ESR_13 0x214 +#define CGU_ESR_FD_EN (0x00000001 << 0) + +#define CGU_FDC_0 0x218 +#define CGU_FDC_1 0x21c +#define CGU_FDC_2 0x220 +#define CGU_FDC_3 0x224 +#define CGU_FDC_4 0x228 +#define CGU_FDC_5 0x22c +#define CGU_FDC_6 0x230 +#define CGU_FDC_7 0x234 +#define CGU_FDC_8 0x238 +#define CGU_FDC_9 0x23c +#define CGU_FDC_10 0x240 +#define CGU_FDC_11 0x244 +#define CGU_FDC_12 0x248 +#define CGU_FDC_13 0x24c +#define CGU_FDC_STRETCH (0x00000001 << 0) +#define CGU_FDC_RESET (0x00000001 << 1) +#define CGU_FDC_RUN1 (0x00000001 << 2) +#define CGU_FDC_MADD (0x000000ff << 3) +#define CGU_FDC_MSUB (0x000000ff << 11) + +/* -------------- DCS Registers -------------- */ + +#define DCS 0x00014000 + +#define DCSC_CTRL 0x000 +#define DCSC_SEL_PLLDI (0x03ffffff << 5) +#define DCSC_TOUT_SEL (0x0000000f << 1) +#define DCSC_TOUT_OFF (0x00000001 << 0) + +#define DCSC_ADDR 0x00c +#define DCSC_ERR_TOUT_ADDR (0x3fffffff << 2) + +#define DCSC_STAT 0x010 +#define DCSC_ERR_TOUT_GNT (0x0000001f << 24) +#define DCSC_ERR_TOUT_SEL (0x0000007f << 10) +#define DCSC_ERR_TOUT_READ (0x00000001 << 8) +#define DCSC_ERR_TOUT_MASK (0x0000000f << 4) +#define DCSC_ERR_ACK (0x00000001 << 1) + +#define DCSC_FEATURES 0x040 +#define DCSC_UNIQUE_ID (0x00000007 << 16) +#define DCSC_SECURITY (0x00000001 << 14) +#define DCSC_NUM_BASE_REGS (0x00000003 << 11) +#define DCSC_NUM_TARGETS (0x0000001f << 5) +#define DCSC_NUM_INITIATORS (0x0000001f << 0) + +#define DCSC_BASE_REG0 0x100 +#define DCSC_BASE_N_REG (0x00000fff << 20) + +#define DCSC_INT_CLR_ENABLE 0xfd8 +#define DCSC_INT_CLR_ENABLE_TOUT (0x00000001 << 1) +#define DCSC_INT_CLR_ENABLE_ERROR (0x00000001 << 0) + +#define DCSC_INT_SET_ENABLE 0xfdc +#define DCSC_INT_SET_ENABLE_TOUT (0x00000001 << 1) +#define DCSC_INT_SET_ENABLE_ERROR (0x00000001 << 0) + +#define DCSC_INT_STATUS 0xfe0 +#define DCSC_INT_STATUS_TOUT (0x00000001 << 1) +#define DCSC_INT_STATUS_ERROR (0x00000001 << 0) + +#define DCSC_INT_ENABLE 0xfe4 +#define DCSC_INT_ENABLE_TOUT (0x00000001 << 1) +#define DCSC_INT_ENABLE_ERROR (0x00000001 << 0) + +#define DCSC_INT_CLR_STATUS 0xfe8 +#define DCSC_INT_CLEAR_TOUT (0x00000001 << 1) +#define DCSC_INT_CLEAR_ERROR (0x00000001 << 0) + +#define DCSC_INT_SET_STATUS 0xfec +#define DCSC_INT_SET_TOUT (0x00000001 << 1) +#define DCSC_INT_SET_ERROR (0x00000001 << 0) + + + + +/* -------------- GREG Registers -------------- */ + +#define GREG 0x00012000 + +#define GREG_SUBSYS_CONFIG 0x000 +#define GREG_SUBSYS_ID (0x0000ffff << 16) +#define GREG_SUBSYS_VID (0x0000ffff << 0) + +#define GREG_MSI_BAR_PMCSR 0x004 +#define GREG_PMCSR_SCALE_7 (0x00000003 << 30) +#define GREG_PMCSR_SCALE_6 (0x00000003 << 28) +#define GREG_PMCSR_SCALE_5 (0x00000003 << 26) +#define GREG_PMCSR_SCALE_4 (0x00000003 << 24) +#define GREG_PMCSR_SCALE_3 (0x00000003 << 22) +#define GREG_PMCSR_SCALE_2 (0x00000003 << 20) +#define GREG_PMCSR_SCALE_1 (0x00000003 << 18) +#define GREG_PMCSR_SCALE_0 (0x00000003 << 16) + +#define GREG_BAR_WIDTH_17 (0x0000001e << 8) +#define GREG_BAR_WIDTH_18 (0x0000001c << 8) +#define GREG_BAR_WIDTH_19 (0x00000018 << 8) +#define GREG_BAR_WIDTH_20 (0x00000010 << 8) + +#define GREG_BAR_PREFETCH (0x00000001 << 3) +#define GREG_MSI_MM_CAP1 (0x00000000 << 0) // FIXME ! +#define GREG_MSI_MM_CAP2 (0x00000001 << 0) +#define GREG_MSI_MM_CAP4 (0x00000002 << 0) +#define GREG_MSI_MM_CAP8 (0x00000003 << 0) +#define GREG_MSI_MM_CAP16 (0x00000004 << 0) +#define GREG_MSI_MM_CAP32 (0x00000005 << 0) + +#define GREG_PMCSR_DATA_1 0x008 +#define GREG_PMCSR_DATA_2 0x00c +#define GREG_VI_CTRL 0x010 +#define GREG_FGPI_CTRL 0x014 + +#define GREG_RSTU_CTRL 0x018 +#define GREG_BOOT_READY (0x00000001 << 13) +#define GREG_RESET_REQ (0x00000001 << 12) +#define GREG_IP_RST_RELEASE (0x00000001 << 11) +#define GREG_ADAPTER_RST_RELEASE (0x00000001 << 10) +#define GREG_PCIE_CORE_RST_RELEASE (0x00000001 << 9) +#define GREG_BOOT_IP_RST_RELEASE (0x00000001 << 8) +#define GREG_BOOT_RST_RELEASE (0x00000001 << 7) +#define GREG_CGU_RST_RELEASE (0x00000001 << 6) +#define GREG_IP_RST_ASSERT (0x00000001 << 5) +#define GREG_ADAPTER_RST_ASSERT (0x00000001 << 4) +#define GREG_RST_ASSERT (0x00000001 << 3) +#define GREG_BOOT_IP_RST_ASSERT (0x00000001 << 2) +#define GREG_BOOT_RST_ASSERT (0x00000001 << 1) +#define GREG_CGU_RST_ASSERT (0x00000001 << 0) + +#define GREG_I2C_CTRL 0x01c +#define GREG_I2C_SLAVE_ADDR (0x0000007f << 0) + +#define GREG_OVFLW_CTRL 0x020 +#define GREG_OVERFLOW_ENABLE (0x00001fff << 0) + +#define GREG_TAG_ACK_FLEN 0x024 +#define GREG_TAG_ACK_FLEN_1B (0x00000000 << 0) +#define GREG_TAG_ACK_FLEN_2B (0x00000001 << 0) +#define GREG_TAG_ACK_FLEN_4B (0x00000002 << 0) +#define GREG_TAG_ACK_FLEN_8B (0x00000003 << 0) + +#define GREG_VIDEO_IN_CTRL 0x028 + +#define GREG_SPARE_1 0x02c +#define GREG_SPARE_2 0x030 +#define GREG_SPARE_3 0x034 +#define GREG_SPARE_4 0x038 +#define GREG_SPARE_5 0x03c +#define GREG_SPARE_6 0x040 +#define GREG_SPARE_7 0x044 +#define GREG_SPARE_8 0x048 +#define GREG_SPARE_9 0x04c +#define GREG_SPARE_10 0x050 +#define GREG_SPARE_11 0x054 +#define GREG_SPARE_12 0x058 +#define GREG_SPARE_13 0x05c +#define GREG_SPARE_14 0x060 +#define GREG_SPARE_15 0x064 + +#define GREG_FAIL_DISABLE 0x068 +#define GREG_BOOT_FAIL_DISABLE (0x00000001 << 0) + +#define GREG_SW_RST 0xff0 +#define GREG_SW_RESET (0x00000001 << 0) + + + + +/* BAR = 20 bits */ + +/* -------------- PHI1 Registers -------------- */ + +#define PHI_1 0x00020000 + + + +#endif /* __SAA716x_REG_H */ diff --git a/drivers/media/common/saa716x/saa716x_rom.c b/drivers/media/common/saa716x/saa716x_rom.c new file mode 100644 index 0000000..7f8dbe1 --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_rom.c @@ -0,0 +1,1071 @@ +#include +#include + +#include "saa716x_rom.h" +#include "saa716x_adap.h" +#include "saa716x_spi.h" +#include "saa716x_priv.h" + +int i; + +static int eeprom_read_bytes(struct saa716x_dev *saa716x, u16 reg, u16 len, u8 *val) +{ + struct saa716x_i2c *i2c = saa716x->i2c; + struct i2c_adapter *adapter = &i2c[SAA716x_I2C_BUS_B].i2c_adapter; + + u8 b0[] = { MSB(reg), LSB(reg) }; + int ret; + + struct i2c_msg msg[] = { + { .addr = 0x50, .flags = 0, .buf = b0, .len = sizeof (b0) }, + { .addr = 0x50, .flags = I2C_M_RD, .buf = val, .len = len } + }; + + ret = i2c_transfer(adapter, msg, 2); + if (ret != 2) { + dprintk(SAA716x_ERROR, 1, "read error ", reg, ret); + return -EREMOTEIO; + } + + return ret; +} + +static int saa716x_read_rombytes(struct saa716x_dev *saa716x, u16 reg, u16 len, u8 *val) +{ + struct saa716x_i2c *i2c = saa716x->i2c; + struct i2c_adapter *adapter = &i2c[SAA716x_I2C_BUS_B].i2c_adapter; + struct i2c_msg msg[2]; + + u8 b0[2]; + int ret, count; + + count = len / DUMP_BYTES; + if (len % DUMP_BYTES) + count++; + + count *= 2; + + for (i = 0; i < count; i += 2) { + dprintk(SAA716x_DEBUG, 1, "Length=%d, Count=%d, Reg=0x%02x", + len, + count, + reg); + + b0[0] = MSB(reg); + b0[1] = LSB(reg); + + /* Write */ + msg[0].addr = 0x50; + msg[0].flags = 0; + msg[0].buf = b0; + msg[0].len = 2; + + /* Read */ + msg[1].addr = 0x50; + msg[1].flags = I2C_M_RD; + msg[1].buf = val; + + if (i == (count - 2)) { + /* last message */ + if (len % DUMP_BYTES) { + msg[1].len = len % DUMP_BYTES; + dprintk(SAA716x_DEBUG, 1, "Last Message length=%d", len % DUMP_BYTES); + } else { + msg[1].len = DUMP_BYTES; + } + } else { + msg[1].len = DUMP_BYTES; + } + + ret = i2c_transfer(adapter, msg, 2); + if (ret != 2) { + dprintk(SAA716x_ERROR, 1, "read error ", reg, ret); + return -EREMOTEIO; + } + + reg += DUMP_BYTES; + val += DUMP_BYTES; + } + + return 0; +} + +static int saa716x_get_offset(struct saa716x_dev *saa716x, u8 *buf, u32 *offset) +{ + int i; + + *offset = 0; + for (i = 0; i < 256; i++) { + if (!(strncmp("START", buf + i, 5))) + break; + } + dprintk(SAA716x_INFO, 1, "Offset @ %d", i); + *offset = i; + + return 0; +} + +static int saa716x_eeprom_header(struct saa716x_dev *saa716x, + struct saa716x_romhdr *rom_header, + u8 *buf, + u32 *offset) +{ + memcpy(rom_header, &buf[*offset], sizeof (struct saa716x_romhdr)); + if (rom_header->header_size != sizeof (struct saa716x_romhdr)) { + dprintk(SAA716x_ERROR, 1, + "ERROR: Header size mismatch! Read size=%d bytes, Expected=%d", + (int)sizeof (struct saa716x_romhdr), + rom_header->header_size); + + return -1; + } + *offset += sizeof (struct saa716x_romhdr); + + dprintk(SAA716x_NOTICE, 0, "SAA%02x ROM: Data=%d bytes\n", + saa716x->pdev->device, + rom_header->data_size); + + dprintk(SAA716x_NOTICE, 0, "SAA%02x ROM: Version=%d\n", + saa716x->pdev->device, + rom_header->version); + + dprintk(SAA716x_NOTICE, 0, "SAA%02x ROM: Devices=%d\n", + saa716x->pdev->device, + rom_header->devices); + + dprintk(SAA716x_NOTICE, 0, "SAA%02x ROM: Compressed=%d\n\n", + saa716x->pdev->device, + rom_header->compression); + + return 0; +} + +int saa716x_dump_eeprom(struct saa716x_dev *saa716x) +{ + struct saa716x_romhdr rom_header; + u8 buf[DUMP_BYTES]; + int i, err = 0; + u32 offset = 0; + + err = eeprom_read_bytes(saa716x, DUMP_OFFST, DUMP_BYTES, buf); + if (err < 0) { + dprintk(SAA716x_ERROR, 1, "EEPROM Read error"); + return err; + } + + dprintk(SAA716x_NOTICE, 0, " Card: %s\n", + saa716x->config->model_name); + + dprintk(SAA716x_NOTICE, 0, + " ---------------- SAA%02x ROM @ Offset 0x%02x ----------------", + saa716x->pdev->device, + DUMP_OFFST); + + for (i = 0; i < DUMP_BYTES; i++) { + if ((i % 16) == 0) { + dprintk(SAA716x_NOTICE, 0, "\n "); + dprintk(SAA716x_NOTICE, 0, "%04x: ", i); + } + + if ((i % 8) == 0) + dprintk(SAA716x_NOTICE, 0, " "); + if ((i % 4) == 0) + dprintk(SAA716x_NOTICE, 0, " "); + dprintk(SAA716x_NOTICE, 0, "%02x ", buf[i]); + } + dprintk(SAA716x_NOTICE, 0, "\n"); + dprintk(SAA716x_NOTICE, 0, + " ---------------- SAA%02x ROM Dump end ---------------------\n\n", + saa716x->pdev->device); + + err = saa716x_get_offset(saa716x, buf, &offset); + if (err != 0) { + dprintk(SAA716x_ERROR, 1, "ERROR: Descriptor not found <%d>", err); + return err; + } + offset += 5; + saa716x->id_offst = offset; + /* Get header */ + err = saa716x_eeprom_header(saa716x, &rom_header, buf, &offset); + if (err != 0) { + dprintk(SAA716x_ERROR, 1, "ERROR: Header Read failed <%d>", err); + return -1; + } + saa716x->id_len = rom_header.data_size; + + return 0; +} +EXPORT_SYMBOL_GPL(saa716x_dump_eeprom); + +static void saa716x_descriptor_dbg(struct saa716x_dev *saa716x, + u8 *buf, + u32 *offset, + u8 size, + u8 ext_size) +{ + int i; + + dprintk(SAA716x_INFO, 0, " "); + for (i = 0; i < 49; i++) + dprintk(SAA716x_INFO, 0, "-"); + + for (i = 0; i < size + ext_size; i++) { + if ((i % 16) == 0) + dprintk(SAA716x_INFO, 0, "\n "); + if ((i % 8) == 0) + dprintk(SAA716x_INFO, 0, " "); + if ((i % 4) == 0) + dprintk(SAA716x_INFO, 0, " "); + + dprintk(SAA716x_INFO, 0, "%02x ", buf[*offset + i]); + } + + dprintk(SAA716x_INFO, 0, "\n "); + for (i = 0; i < 49; i++) + dprintk(SAA716x_INFO, 0, "-"); + dprintk(SAA716x_INFO, 0, "\n"); + +} + +static int saa716x_decoder_info(struct saa716x_dev *saa716x, + u8 *buf, + u32 *offset) +{ + struct saa716x_decoder_hdr header; + + memcpy(&header, &buf[*offset], sizeof (struct saa716x_decoder_hdr)); + saa716x_descriptor_dbg(saa716x, buf, offset, header.size, header.ext_data); + if (header.size != sizeof (struct saa716x_decoder_hdr)) { + dprintk(SAA716x_ERROR, 1, + "ERROR: Header size mismatch! Read size=%d bytes, Expected=%d", + header.size, + (int)sizeof (struct saa716x_decoder_hdr)); + + return -1; + } + + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Size=%d bytes\n", + saa716x->pdev->device, + header.size); + + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Ext Data=%d bytes\n\n", + saa716x->pdev->device, + header.ext_data); + + *offset += header.size + header.ext_data; + return 0; +} + +static int saa716x_gpio_info(struct saa716x_dev *saa716x, + u8 *buf, + u32 *offset) +{ + struct saa716x_gpio_hdr header; + + memcpy(&header, &buf[*offset], sizeof (struct saa716x_gpio_hdr)); + saa716x_descriptor_dbg(saa716x, buf, offset, header.size, header.ext_data); + if (header.size != sizeof (struct saa716x_gpio_hdr)) { + dprintk(SAA716x_ERROR, 1, + "ERROR: Header size mismatch! Read size=%d bytes, Expected=%d", + header.size, + (int)sizeof (struct saa716x_gpio_hdr)); + + return -1; + } + + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Size=%d bytes\n", + saa716x->pdev->device, + header.size); + + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Pins=%d\n", + saa716x->pdev->device, + header.pins); + + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Ext data=%d\n\n", + saa716x->pdev->device, + header.ext_data); + + *offset += header.size + header.ext_data; + + return 0; +} + +static int saa716x_video_decoder_info(struct saa716x_dev *saa716x, + u8 *buf, + u32 *offset) +{ + struct saa716x_video_decoder_hdr header; + + memcpy(&header, &buf[*offset], sizeof (struct saa716x_video_decoder_hdr)); + saa716x_descriptor_dbg(saa716x, buf, offset, header.size, header.ext_data); + if (header.size != sizeof (struct saa716x_video_decoder_hdr)) { + dprintk(SAA716x_ERROR, 1, + "ERROR: Header size mismatch! Read size=%d bytes, Expected=%d", + header.size, + (int)sizeof (struct saa716x_video_decoder_hdr)); + + return -1; + } + + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Size=%d bytes\n", + saa716x->pdev->device, + header.size); + + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: PORT 0=0x%02x\n", + saa716x->pdev->device, + header.video_port0); + + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: PORT 1=0x%02x\n", + saa716x->pdev->device, + header.video_port1); + + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: PORT 2=0x%02x\n", + saa716x->pdev->device, + header.video_port2); + + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: VBI PORT ID=0x%02x\n", + saa716x->pdev->device, + header.vbi_port_id); + + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Video PORT Type=0x%02x\n", + saa716x->pdev->device, + header.video_port_type); + + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: VBI PORT Type=0x%02x\n", + saa716x->pdev->device, + header.vbi_port_type); + + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Encoder PORT Type=0x%02x\n", + saa716x->pdev->device, + header.encoder_port_type); + + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Video Output=0x%02x\n", + saa716x->pdev->device, + header.video_output); + + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: VBI Output=0x%02x\n", + saa716x->pdev->device, + header.vbi_output); + + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Encoder Output=0x%02x\n", + saa716x->pdev->device, + header.encoder_output); + + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Ext data=%d bytes\n\n", + saa716x->pdev->device, + header.ext_data); + + *offset += header.size + header.ext_data; + return 0; +} + +static int saa716x_audio_decoder_info(struct saa716x_dev *saa716x, + u8 *buf, + u32 *offset) +{ + struct saa716x_audio_decoder_hdr header; + + memcpy(&header, &buf[*offset], sizeof (struct saa716x_audio_decoder_hdr)); + saa716x_descriptor_dbg(saa716x, buf, offset, header.size, header.ext_data); + if (header.size != sizeof (struct saa716x_audio_decoder_hdr)) { + dprintk(SAA716x_ERROR, 1, + "ERROR: Header size mismatch! Read size=%d bytes, Expected=%d", + header.size, + (int)sizeof (struct saa716x_audio_decoder_hdr)); + + return -1; + } + + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Size=%d bytes\n", + saa716x->pdev->device, + header.size); + + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Ext data=%d bytes\n\n", + saa716x->pdev->device, + header.ext_data); + + *offset += header.size + header.ext_data; + return 0; +} + +static int saa716x_event_source_info(struct saa716x_dev *saa716x, + u8 *buf, + u32 *offset) +{ + struct saa716x_evsrc_hdr header; + + memcpy(&header, &buf[*offset], sizeof (struct saa716x_evsrc_hdr)); + saa716x_descriptor_dbg(saa716x, buf, offset, header.size, header.ext_data); + if (header.size != sizeof (struct saa716x_evsrc_hdr)) { + dprintk(SAA716x_ERROR, 1, + "ERROR: Header size mismatch! Read size=%d bytes, Expected=%d", + header.size, + (int)sizeof (struct saa716x_evsrc_hdr)); + + return -1; + } + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Size=%d bytes\n", + saa716x->pdev->device, + header.size); + + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Ext data=%d bytes\n\n", + saa716x->pdev->device, + header.ext_data); + + *offset += header.size + header.ext_data; + return 0; +} + +static int saa716x_crossbar_info(struct saa716x_dev *saa716x, + u8 *buf, + u32 *offset) +{ + struct saa716x_xbar_hdr header; + struct saa716x_xbar_pair_info pair_info; + + memcpy(&header, &buf[*offset], sizeof (struct saa716x_xbar_hdr)); + saa716x_descriptor_dbg(saa716x, buf, offset, header.size, header.ext_data); + if (header.size != sizeof (struct saa716x_xbar_hdr)) { + dprintk(SAA716x_ERROR, 1, + "ERROR: Header size mismatch! Read size=%d bytes, Expected=%d", + header.size, + (int)sizeof (struct saa716x_xbar_hdr)); + + return -1; + } + + memcpy(&pair_info, &buf[*offset], sizeof (struct saa716x_xbar_pair_info)); + + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Size=%d bytes\n", + saa716x->pdev->device, + header.size); + + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Pairs=%d\n", + saa716x->pdev->device, + header.pair_inputs); + + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Ext data=%d bytes\n\n", + saa716x->pdev->device, + header.ext_data); + + *offset += header.size + header.ext_data + (sizeof (struct saa716x_xbar_pair_info) * header.pair_inputs); + return 0; +} + +static int saa716x_tuner_info(struct saa716x_dev *saa716x, + u8 *buf, + u32 *offset) +{ + struct saa716x_tuner_hdr header; + + memcpy(&header, &buf[*offset], sizeof (struct saa716x_tuner_hdr)); + saa716x_descriptor_dbg(saa716x, buf, offset, header.size, header.ext_data); + if (header.size != sizeof (struct saa716x_tuner_hdr)) { + dprintk(SAA716x_ERROR, 1, + "ERROR: Header size mismatch! Read size=%d bytes, Expected=%d", + header.size, + (int)sizeof (struct saa716x_tuner_hdr)); + + return -1; + } + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Size=%d bytes\n", + saa716x->pdev->device, + header.size); + + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Ext data=%d bytes\n\n", + saa716x->pdev->device, + header.ext_data); + + *offset += header.size + header.ext_data; + return 0; +} + +static int saa716x_pll_info(struct saa716x_dev *saa716x, + u8 *buf, + u32 *offset) +{ + struct saa716x_pll_hdr header; + + memcpy(&header, &buf[*offset], sizeof (struct saa716x_pll_hdr)); + saa716x_descriptor_dbg(saa716x, buf, offset, header.size, header.ext_data); + if (header.size != sizeof (struct saa716x_pll_hdr)) { + dprintk(SAA716x_ERROR, 1, + "ERROR: Header size mismatch! Read size=%d bytes, Expected=%d", + header.size, + (int)sizeof (struct saa716x_pll_hdr)); + + return -1; + } + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Size=%d bytes\n", + saa716x->pdev->device, + header.size); + + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Ext data=%d bytes\n\n", + saa716x->pdev->device, + header.ext_data); + + *offset += header.size + header.ext_data; + return 0; +} + +static int saa716x_channel_decoder_info(struct saa716x_dev *saa716x, + u8 *buf, + u32 *offset) +{ + struct saa716x_channel_decoder_hdr header; + + memcpy(&header, &buf[*offset], sizeof (struct saa716x_channel_decoder_hdr)); + saa716x_descriptor_dbg(saa716x, buf, offset, header.size, header.ext_data); + if (header.size != sizeof (struct saa716x_channel_decoder_hdr)) { + dprintk(SAA716x_ERROR, 1, + "ERROR: Header size mismatch! Read size=%d bytes, Expected=%d", + header.size, + (int)sizeof (struct saa716x_channel_decoder_hdr)); + + return -1; + } + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Size=%d bytes\n", + saa716x->pdev->device, + header.size); + + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Ext data=%d bytes\n\n", + saa716x->pdev->device, + header.ext_data); + + *offset += header.size + header.ext_data; + return 0; +} + +static int saa716x_encoder_info(struct saa716x_dev *saa716x, + u8 *buf, + u32 *offset) +{ + struct saa716x_encoder_hdr header; + + memcpy(&header, &buf[*offset], sizeof (struct saa716x_encoder_hdr)); + saa716x_descriptor_dbg(saa716x, buf, offset, header.size, header.ext_data); + if (header.size != sizeof (struct saa716x_encoder_hdr)) { + dprintk(SAA716x_ERROR, 1, + "ERROR: Header size mismatch! Read size=%d bytes, Expected=%d", + header.size, + (int)sizeof (struct saa716x_encoder_hdr)); + + return -1; + } + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Size=%d bytes\n", + saa716x->pdev->device, + header.size); + + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Ext data=%d bytes\n\n", + saa716x->pdev->device, + header.ext_data); + + *offset += header.size + header.ext_data; + return 0; +} + +static int saa716x_ir_info(struct saa716x_dev *saa716x, + u8 *buf, + u32 *offset) +{ + struct saa716x_ir_hdr header; + + memcpy(&header, &buf[*offset], sizeof (struct saa716x_ir_hdr)); + saa716x_descriptor_dbg(saa716x, buf, offset, header.size, header.ext_data); + if (header.size != sizeof (struct saa716x_ir_hdr)) { + dprintk(SAA716x_ERROR, 1, + "ERROR: Header size mismatch! Read size=%d bytes, Expected=%d", + header.size, + (int)sizeof (struct saa716x_ir_hdr)); + + return -1; + } + + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Size=%d bytes\n", + saa716x->pdev->device, + header.size); + + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Ext data=%d bytes\n\n", + saa716x->pdev->device, + header.ext_data); + + *offset += header.size + header.ext_data; + return 0; +} + +static int saa716x_eeprom_info(struct saa716x_dev *saa716x, + u8 *buf, + u32 *offset) +{ + struct saa716x_eeprom_hdr header; + + memcpy(&header, &buf[*offset], sizeof (struct saa716x_eeprom_hdr)); + saa716x_descriptor_dbg(saa716x, buf, offset, header.size, header.ext_data); + if (header.size != sizeof (struct saa716x_eeprom_hdr)) { + dprintk(SAA716x_ERROR, 1, + "ERROR: Header size mismatch! Read size=%d bytes, Expected=%d", + header.size, + (int)sizeof (struct saa716x_eeprom_hdr)); + + return -1; + } + + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Size=%d bytes\n", + saa716x->pdev->device, + header.size); + + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Ext data=%d bytes\n\n", + saa716x->pdev->device, + header.ext_data); + + *offset += header.size + header.ext_data; + return 0; +} + +static int saa716x_filter_info(struct saa716x_dev *saa716x, + u8 *buf, + u32 *offset) +{ + struct saa716x_filter_hdr header; + + memcpy(&header, &buf[*offset], sizeof (struct saa716x_filter_hdr)); + saa716x_descriptor_dbg(saa716x, buf, offset, header.size, header.ext_data); + if (header.size != sizeof (struct saa716x_filter_hdr)) { + dprintk(SAA716x_ERROR, 1, + "ERROR: Header size mismatch! Read size=%d bytes, Expected=%d", + header.size, + (int)sizeof(struct saa716x_filter_hdr)); + + return -1; + } + + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Size=%d bytes\n", + saa716x->pdev->device, + header.size); + + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Ext data=%d bytes\n", + saa716x->pdev->device, + header.ext_data); + + *offset += header.size + header.ext_data; + return 0; +} + +static int saa716x_streamdev_info(struct saa716x_dev *saa716x, + u8 *buf, + u32 *offset) +{ + struct saa716x_streamdev_hdr header; + + memcpy(&header, &buf[*offset], sizeof (struct saa716x_streamdev_hdr)); + saa716x_descriptor_dbg(saa716x, buf, offset, header.size, header.ext_data); + if (header.size != sizeof (struct saa716x_streamdev_hdr)) { + dprintk(SAA716x_ERROR, 1, + "ERROR: Header size mismatch! Read size=%d bytes, Expected=%d", + header.size, + (int)sizeof(struct saa716x_streamdev_hdr)); + + return -1; + } + + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Size=%d bytes\n", + saa716x->pdev->device, + header.size); + + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Ext data=%d bytes\n", + saa716x->pdev->device, + header.ext_data); + + *offset += header.size + header.ext_data; + return 0; +} + +static int saa716x_unknown_device_info(struct saa716x_dev *saa716x, + u8 *buf, + u32 *offset) +{ + u8 size; + u8 ext_size = 0; + + size = buf[*offset]; + if (size > 1) + ext_size = buf[*offset + size -1]; + + saa716x_descriptor_dbg(saa716x, buf, offset, size, ext_size); + + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Size=%d bytes\n", + saa716x->pdev->device, + size); + + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Ext data=%d bytes\n\n", + saa716x->pdev->device, + ext_size); + + *offset += size + ext_size; + return 0; +} + + +static void saa716x_device_dbg(struct saa716x_dev *saa716x, + u8 *buf, + u32 *offset, + u8 size, + u8 ext_size, + u8 addr_size) +{ + int i; + + dprintk(SAA716x_INFO, 0, " "); + for (i = 0; i < 53; i++) + dprintk(SAA716x_INFO, 0, "-"); + + for (i = 0; i < size + ext_size + addr_size; i++) { + if ((i % 16) == 0) + dprintk(SAA716x_INFO, 0, "\n "); + if ((i % 8) == 0) + dprintk(SAA716x_INFO, 0, " "); + if ((i % 4) == 0) + dprintk(SAA716x_INFO, 0, " "); + + dprintk(SAA716x_INFO, 0, "%02x ", buf[*offset + i]); + } + + dprintk(SAA716x_INFO, 0, "\n "); + for (i = 0; i < 53; i++) + dprintk(SAA716x_INFO, 0, "-"); + dprintk(SAA716x_INFO, 0, "\n"); + +} + + +static int saa716x_device_info(struct saa716x_dev *saa716x, + struct saa716x_devinfo *device, + u8 *buf, + u32 *offset) +{ + u8 address = 0; + + memcpy(device, &buf[*offset], sizeof(struct saa716x_devinfo)); + if (device->struct_size != sizeof(struct saa716x_devinfo)) { + dprintk(SAA716x_ERROR, 1, "ERROR: Device size mismatch! Read=%d bytes, expected=%d bytes", + device->struct_size, + (int)sizeof(struct saa716x_devinfo)); + + return -1; + } + + saa716x_device_dbg(saa716x, + buf, + offset, + device->struct_size, + device->extd_data_size, + device->addr_size); + + *offset += device->struct_size; + + if (device->addr_size) { + address = buf[*offset]; + address >>= 1; + *offset += device->addr_size; + } + + dprintk(SAA716x_NOTICE, 0, " SAA%02x ROM: Device @ 0x%02x\n", + saa716x->pdev->device, + address); + + dprintk(SAA716x_NOTICE, 0, " SAA%02x ROM: Size=%d bytes\n", + saa716x->pdev->device, + device->struct_size); + + dprintk(SAA716x_NOTICE, 0, " SAA%02x ROM: Device ID=0x%02x\n", + saa716x->pdev->device, + device->device_id); + + dprintk(SAA716x_NOTICE, 0, " SAA%02x ROM: Master ID=0x%02x\n", + saa716x->pdev->device, + device->master_devid); + + dprintk(SAA716x_NOTICE, 0, " SAA%02x ROM: Bus ID=0x%02x\n", + saa716x->pdev->device, + device->master_busid); + + dprintk(SAA716x_NOTICE, 0, " SAA%02x ROM: Device type=0x%02x\n", + saa716x->pdev->device, + device->device_type); + + dprintk(SAA716x_NOTICE, 0, " SAA%02x ROM: Implementation ID=0x%02x\n", + saa716x->pdev->device, + device->implem_id); + + dprintk(SAA716x_NOTICE, 0, " SAA%02x ROM: Path ID=0x%02x\n", + saa716x->pdev->device, + device->path_id); + + dprintk(SAA716x_NOTICE, 0, " SAA%02x ROM: GPIO ID=0x%02x\n", + saa716x->pdev->device, + device->gpio_id); + + dprintk(SAA716x_NOTICE, 0, " SAA%02x ROM: Address=%d bytes\n", + saa716x->pdev->device, + device->addr_size); + + dprintk(SAA716x_NOTICE, 0, " SAA%02x ROM: Extended data=%d bytes\n\n", + saa716x->pdev->device, + device->extd_data_size); + + if (device->extd_data_size) { + u32 mask; + + mask = 0x00000001; + while (mask) { + if (device->device_type & mask) { + switch (mask) { + case DECODER_DEVICE: + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Found decoder device\n", + saa716x->pdev->device); + + saa716x_decoder_info(saa716x, buf, offset); + break; + + case GPIO_SOURCE: + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Found GPIO device\n", + saa716x->pdev->device); + + saa716x_gpio_info(saa716x, buf, offset); + break; + + case VIDEO_DECODER: + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Found Video Decoder device\n", + saa716x->pdev->device); + + saa716x_video_decoder_info(saa716x, buf, offset); + break; + + case AUDIO_DECODER: + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Found Audio Decoder device\n", + saa716x->pdev->device); + + saa716x_audio_decoder_info(saa716x, buf, offset); + break; + + case EVENT_SOURCE: + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Found Event source\n", + saa716x->pdev->device); + + saa716x_event_source_info(saa716x, buf, offset); + break; + + case CROSSBAR: + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Found Crossbar device\n", + saa716x->pdev->device); + + saa716x_crossbar_info(saa716x, buf, offset); + break; + + case TUNER_DEVICE: + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Found Tuner device\n", + saa716x->pdev->device); + + saa716x_tuner_info(saa716x, buf, offset); + break; + + case PLL_DEVICE: + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Found PLL device\n", + saa716x->pdev->device); + + saa716x_pll_info(saa716x, buf, offset); + break; + + case CHANNEL_DECODER: + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Found Channel Demodulator device\n", + saa716x->pdev->device); + + saa716x_channel_decoder_info(saa716x, buf, offset); + break; + + case RDS_DECODER: + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Found RDS Decoder device\n", + saa716x->pdev->device); + + saa716x_unknown_device_info(saa716x, buf, offset); + break; + + case ENCODER_DEVICE: + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Found Encoder device\n", + saa716x->pdev->device); + + saa716x_encoder_info(saa716x, buf, offset); + break; + + case IR_DEVICE: + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Found IR device\n", + saa716x->pdev->device); + + saa716x_ir_info(saa716x, buf, offset); + break; + + case EEPROM_DEVICE: + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Found EEPROM device\n", + saa716x->pdev->device); + + saa716x_eeprom_info(saa716x, buf, offset); + break; + + case NOISE_FILTER: + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Found Noise filter device\n", + saa716x->pdev->device); + + saa716x_filter_info(saa716x, buf, offset); + break; + + case LNx_DEVICE: + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Found LNx device\n", + saa716x->pdev->device); + + saa716x_unknown_device_info(saa716x, buf, offset); + break; + + case STREAM_DEVICE: + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Found streaming device\n", + saa716x->pdev->device); + + saa716x_streamdev_info(saa716x, buf, offset); + break; + + case CONFIGSPACE_DEVICE: + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Found Configspace device\n", + saa716x->pdev->device); + + saa716x_unknown_device_info(saa716x, buf, offset); + break; + + default: + dprintk(SAA716x_NOTICE, 0, + " SAA%02x ROM: Found unknown device\n", + saa716x->pdev->device); + + saa716x_unknown_device_info(saa716x, buf, offset); + break; + } + } + mask <<= 1; + } + } + + dprintk(SAA716x_NOTICE, 0, "\n"); + + return 0; +} + +int saa716x_eeprom_data(struct saa716x_dev *saa716x) +{ + struct saa716x_romhdr rom_header; + struct saa716x_devinfo *device; + + u8 buf[1024]; + int i, ret = 0; + u32 offset = 0; + + /* dump */ + ret = saa716x_read_rombytes(saa716x, saa716x->id_offst, saa716x->id_len + 8, buf); + if (ret < 0) { + dprintk(SAA716x_ERROR, 1, "EEPROM Read error <%d>", ret); + goto err0; + } + + /* Get header */ + ret = saa716x_eeprom_header(saa716x, &rom_header, buf, &offset); + if (ret != 0) { + dprintk(SAA716x_ERROR, 1, "ERROR: Header Read failed <%d>", ret); + goto err0; + } + + /* allocate for device info */ + device = kzalloc(sizeof (struct saa716x_devinfo) * rom_header.devices, GFP_KERNEL); + if (device == NULL) { + dprintk(SAA716x_ERROR, 1, "ERROR: out of memory"); + goto err0; + } + + for (i = 0; i < rom_header.devices; i++) { + dprintk(SAA716x_NOTICE, 0, " SAA%02x ROM: ===== Device %d =====\n", + saa716x->pdev->device, + i); + + ret = saa716x_device_info(saa716x, &device[i], buf, &offset); + if (ret != 0) { + dprintk(SAA716x_ERROR, 1, "ERROR: Device info read failed <%d>", ret); + goto err1; + } + } + + kfree(device); + + return 0; + +err1: + kfree(device); + +err0: + return ret; +} +EXPORT_SYMBOL_GPL(saa716x_eeprom_data); diff --git a/drivers/media/common/saa716x/saa716x_rom.h b/drivers/media/common/saa716x/saa716x_rom.h new file mode 100644 index 0000000..6bb317f --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_rom.h @@ -0,0 +1,253 @@ +#ifndef __SAA716x_ROM_H +#define __SAA716x_ROM_H + + +#define MSB(__x) ((__x >> 8) & 0xff) +#define LSB(__x) (__x & 0xff) + +#define DUMP_BYTES 0xf0 +#define DUMP_OFFST 0x000 + +struct saa716x_dev; + +struct saa716x_romhdr { + u16 header_size; + u8 compression; + u8 version; + u16 data_size; + u8 devices; + u8 checksum; +} __attribute__((packed)); + +struct saa716x_devinfo { + u8 struct_size; + u8 device_id; + u8 master_devid; + u8 master_busid; + u32 device_type; + u16 implem_id; + u8 path_id; + u8 gpio_id; + u16 addr_size; + u16 extd_data_size; +} __attribute__((packed)); + +enum saa716x_device_types { + DECODER_DEVICE = 0x00000001, + GPIO_SOURCE = 0x00000002, + VIDEO_DECODER = 0x00000004, + AUDIO_DECODER = 0x00000008, + EVENT_SOURCE = 0x00000010, + CROSSBAR = 0x00000020, + TUNER_DEVICE = 0x00000040, + PLL_DEVICE = 0x00000080, + CHANNEL_DECODER = 0x00000100, + RDS_DECODER = 0x00000200, + ENCODER_DEVICE = 0x00000400, + IR_DEVICE = 0x00000800, + EEPROM_DEVICE = 0x00001000, + NOISE_FILTER = 0x00002000, + LNx_DEVICE = 0x00004000, + STREAM_DEVICE = 0x00010000, + CONFIGSPACE_DEVICE = 0x80000000 +}; + +struct saa716x_decoder_hdr { + u8 size; + u8 ext_data; +}; + +struct saa716x_decoder_info { + struct saa716x_decoder_hdr decoder_hdr; + u8 *ext_data; +}; + +struct saa716x_gpio_hdr { + u8 size; + u8 pins; + u8 rsvd; + u8 ext_data; +}; + +struct saa716x_gpio_info { + struct saa716x_gpio_hdr gpio_hdr; + u8 *ext_data; +}; + +struct saa716x_video_decoder_hdr { + u8 size; + u8 video_port0; + u8 video_port1; + u8 video_port2; + u8 vbi_port_id; + u8 video_port_type; + u8 vbi_port_type; + u8 encoder_port_type; + u8 video_output; + u8 vbi_output; + u8 encoder_output; + u8 ext_data; +}; + +struct saa716x_video_decoder_info { + struct saa716x_video_decoder_hdr decoder_hdr; + u8 *ext_data; +}; + +struct saa716x_audio_decoder_hdr { + u8 size; + u8 port; + u8 output; + u8 ext_data; +}; + +struct saa716x_audio_decoder_info { + struct saa716x_audio_decoder_hdr decoder_hdr; + u8 *ext_data; +}; + +struct saa716x_evsrc_hdr { + u8 size; + u8 master_devid; + u16 condition_id; + u8 rsvd; + u8 ext_data; +}; + +struct saa716x_evsrc_info { + struct saa716x_evsrc_hdr evsrc_hdr; + u8 *ext_data; +}; + +enum saa716x_input_pair_type { + TUNER_SIF = 0x00, + TUNER_LINE = 0x01, + TUNER_SPDIF = 0x02, + TUNER_NONE = 0x03, + CVBS_LINE = 0x04, + CVBS_SPDIF = 0x05, + CVBS_NONE = 0x06, + YC_LINE = 0x07, + YC_SPDIF = 0x08, + YC_NONE = 0x09, + YPbPr_LINE = 0x0a, + YPbPr_SPDIF = 0x0b, + YPbPr_NONE = 0x0c, + NO_LINE = 0x0d, + NO_SPDIF = 0x0e, + RGB_LINE = 0x0f, + RGB_SPDIF = 0x10, + RGB_NONE = 0x11 +}; + +struct saa716x_xbar_pair_info { + u8 pair_input_type; + u8 video_input_id; + u8 audio_input_id; +}; + +struct saa716x_xbar_hdr { + u8 size; + u8 pair_inputs; + u8 pair_route_default; + u8 ext_data; +}; + +struct saa716x_xbar_info { + struct saa716x_xbar_hdr xbar_hdr; + struct saa716x_xbar_pair_info *pair_info; + u8 *ext_data; +}; + +struct saa716x_tuner_hdr { + u8 size; + u8 ext_data; +}; + +struct saa716x_tuner_info { + struct saa716x_tuner_hdr tuner_hdr; + u8 *ext_data; +}; + +struct saa716x_pll_hdr { + u8 size; + u8 ext_data; +}; + +struct saa716x_pll_info { + struct saa716x_pll_hdr pll_hdr; + u8 *ext_data; +}; + +struct saa716x_channel_decoder_hdr { + u8 size; + u8 port; + u8 ext_data; +}; + +struct saa716x_channel_decoder_info { + struct saa716x_channel_decoder_hdr channel_dec_hdr; + u8 *ext_data; +}; + +struct saa716x_encoder_hdr { + u8 size; + u8 stream_port0; + u8 stream_port1; + u8 ext_data; +}; + +struct saa716x_encoder_info { + struct saa716x_encoder_hdr encoder_hdr; + u8 *ext_data; +}; + +struct saa716x_ir_hdr { + u8 size; + u8 ir_caps; + u8 ext_data; +}; + +struct saa716x_ir_info { + struct saa716x_ir_hdr ir_hdr; + u8 *ext_data; +}; + +struct saa716x_eeprom_hdr { + u8 size; + u8 rel_device; + u8 ext_data; +}; + +struct saa716x_eeprom_info { + struct saa716x_eeprom_hdr eeprom_hdr; + u8 *ext_data; +}; + +struct saa716x_filter_hdr { + u8 size; + u8 video_decoder; + u8 audio_decoder; + u8 event_source; + u8 ext_data; +}; + +struct saa716x_filter_info { + struct saa716x_filter_hdr filter_hdr; + u8 *ext_data; +}; + +struct saa716x_streamdev_hdr { + u8 size; + u8 ext_data; +}; + +struct saa716x_streamdev_info { + struct saa716x_streamdev_hdr streamdev_hdr; + u8 *ext_data; +}; + +extern int saa716x_dump_eeprom(struct saa716x_dev *saa716x); +extern int saa716x_eeprom_data(struct saa716x_dev *saa716x); + +#endif /* __SAA716x_ROM_H */ diff --git a/drivers/media/common/saa716x/saa716x_spi.c b/drivers/media/common/saa716x/saa716x_spi.c new file mode 100644 index 0000000..8859454 --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_spi.c @@ -0,0 +1,313 @@ +#include +#include +#include +#include + +#include + +#include "saa716x_mod.h" + +#include "saa716x_spi_reg.h" +#include "saa716x_spi.h" +#include "saa716x_priv.h" + +#if 0 // not needed atm +int saa716x_spi_irqevent(struct saa716x_dev *saa716x) +{ + u32 stat, mask; + + BUG_ON(saa716x == NULL); + + stat = SAA716x_EPRD(SPI, SPI_STATUS); + mask = SAA716x_EPRD(SPI, SPI_CONTROL_REG) & SPI_SERIAL_INTER_ENABLE; + if ((!stat && !mask)) + return -1; + + dprintk(SAA716x_DEBUG, 0, "SPI event: Stat=<%02x>", stat); + + if (stat & SPI_TRANSFER_FLAG) + dprintk(SAA716x_DEBUG, 0, " "); + if (stat & SPI_WRITE_COLLISSION) + dprintk(SAA716x_DEBUG, 0, " "); + if (stat & SPI_READ_OVERRUN) + dprintk(SAA716x_DEBUG, 0, " "); + if (stat & SPI_MODE_FAULT) + dprintk(SAA716x_DEBUG, 0, " "); + if (stat & SPI_SLAVE_ABORT) + dprintk(SAA716x_DEBUG, 0, " "); + + return 0; +} +#endif + +void saa716x_spi_write(struct saa716x_dev *saa716x, const u8 *data, int length) +{ + int i; + u32 value; + int rounds; + + for (i = 0; i < length; i++) { + SAA716x_EPWR(SPI, SPI_DATA, data[i]); + rounds = 0; + value = SAA716x_EPRD(SPI, SPI_STATUS); + + while ((value & SPI_TRANSFER_FLAG) == 0 && rounds < 5000) { + value = SAA716x_EPRD(SPI, SPI_STATUS); + rounds++; + } + } +} +EXPORT_SYMBOL_GPL(saa716x_spi_write); + +#if 0 // not needed atm +static int saa716x_spi_status(struct saa716x_dev *saa716x, u32 *status) +{ + u32 stat; + + stat = SAA716x_EPRD(SPI, SPI_STATUS); + + if (stat & SPI_TRANSFER_FLAG) + dprintk(SAA716x_DEBUG, 1, "Transfer complete <%02x>", stat); + + if (stat & SPI_WRITE_COLLISSION) + dprintk(SAA716x_DEBUG, 1, "Write collission <%02x>", stat); + + if (stat & SPI_READ_OVERRUN) + dprintk(SAA716x_DEBUG, 1, "Read Overrun <%02x>", stat); + + if (stat & SPI_MODE_FAULT) + dprintk(SAA716x_DEBUG, 1, "MODE fault <%02x>", stat); + + if (stat & SPI_SLAVE_ABORT) + dprintk(SAA716x_DEBUG, 1, "SLAVE abort <%02x>", stat); + + *status = stat; + + return 0; +} + +#define SPI_CYCLE_TIMEOUT 100 + +static int saa716x_spi_xfer(struct saa716x_dev *saa716x, u32 *data) +{ + u32 i, status = 0; + + /* write data and wait for completion */ + SAA716x_EPWR(SPI, SPI_DATA, data[i]); + for (i = 0; i < SPI_CYCLE_TIMEOUT; i++) { + msleep(10); + saa716x_spi_status(saa716x, &status); +#if 0 + if (status & SPI_TRANSFER_FLAG) { + data = SAA716x_EPRD(SPI, SPI_DATA); + return 0; + } +#endif + if (status & (SPI_WRITE_COLLISSION | + SPI_READ_OVERRUN | + SPI_MODE_FAULT | + SPI_SLAVE_ABORT)) + + return -EIO; + } + + return -EIO; +} + +#if 0 +static int saa716x_spi_wr(struct saa716x_dev *saa716x, const u8 *data, int length) +{ + struct saa716x_spi_config *config = saa716x->spi_config; + u32 gpio_mask; + int ret = 0; + + // protect against multiple access + spin_lock(&saa716x->gpio_lock); + + // configure the module + saa716x_spi_config(saa716x); + + // check input + + // change polarity of GPIO if active high + if (config->active_hi) { + select = 1; + release = 0; + } + + // configure GPIO, first set output register to low selected level + saa716x_gpio_write(saa716x, gpio, select); + + // set mode register to register controlled (0) + gpio_mask = (1 << gpio); + saa716x_set_gpio_mode(saa716x, gpio_mask, 0); + + // configure bit as output (0) + saa716x_gpio_ctl(saa716x, gpio_mask, 0); + + // wait at least 500ns before sending a byte + msleep(1); + + // send command + for (i = 0; i < dwCommandSize; i++) { + ucData = 0; +// dwStatus = TransferData(pucCommand[i], &ucData); + ret = saa716x_spi_xfer(saa716x); + //tmDBGPRINTEx(4,("Info: Command 0x%x ", pucCommand[i] )); + + /* If command length > 1, disable CS at the end of each command. + * But after the last command byte CS must be left active! + */ + if ((dwCommandSize > 1) && (i < dwCommandSize - 1)) { + + saa716x_gpio_write(saa716x, gpio, release); + msleep(1); /* 500 nS minimum */ + saa716x_gpio_write(saa716x, gpio, select); + } + + if (ret != 0) { + dprintk(SAA716x_ERROR, 1, "ERROR: Command transfer failed"); + msleep(1); /* 500 nS minimum */ + saa716x_gpio_write(saa716x, gpio, release); /* release GPIO */ + spin_unlock(&saa716x->spi_lock); + return ret; + } + + if (config->LSB_first) + dwTransferByte++; + else + dwTransferByte--; + } + +// assume that the byte order is the same as the bit order + +// send read address + +// send data + +// wait at least 500ns before releasing slave + +// release GPIO pin + + // release spinlock + spin_unlock(&saa716x->gpio_lock); +} +#endif + +#define MODEBITS (SPI_CPOL | SPI_CPHA) + +static int saa716x_spi_setup(struct spi_device *spi) +{ + struct spi_master *master = spi->master; + struct saa716x_spi_state *saa716x_spi = spi_master_get_devdata(master); + struct saa716x_dev *saa716x = saa716x_spi->saa716x; + struct saa716x_spi_config *config = &saa716x->spi_config; + + u8 control = 0; + + if (spi->mode & ~MODEBITS) { + dprintk(SAA716x_ERROR, 1, "ERROR: Unsupported MODE bits <%x>", + spi->mode & ~MODEBITS); + + return -EINVAL; + } + + SAA716x_EPWR(SPI, SPI_CLOCK_COUNTER, config->clk_count); + + control |= SPI_MODE_SELECT; /* SPI Master */ + + if (config->LSB_first) + control |= SPI_LSB_FIRST_ENABLE; + + if (config->clk_pol) + control |= SPI_CLOCK_POLARITY; + + if (config->clk_pha) + control |= SPI_CLOCK_PHASE; + + SAA716x_EPWR(SPI, SPI_CONTROL_REG, control); + + return 0; +} + +static void saa716x_spi_cleanup(struct spi_device *spi) +{ + +} + +static int saa716x_spi_transfer(struct spi_device *spi, struct spi_message *msg) +{ + struct spi_master *master = spi->master; + struct saa716x_spi_state *saa716x_spi = spi_master_get_devdata(master); + struct saa716x_dev *saa716x = saa716x_spi->saa716x; + unsigned long flags; + + spin_lock_irqsave(&saa716x->gpio_lock, flags); +#if 0 + if (saa716x_spi->run == QUEUE_STOPPED) { + spin_unlock_irqrestore(&saa716x_spi->lock, flags); + return -ESHUTDOWN; + } + + msg->actual_length = 0; + msg->status = -EINPROGRESS; + msg->state = START_STATE; + + list_add_tail(&msg->queue, &saa716x_spi->queue); + + if (saa716x_spi->run == QUEUE_RUNNING && !saa716x_spi->busy) + queue_work(saa716x_spi->workqueue, &saa716x_spi->pump_messages); +#endif + spin_unlock_irqrestore(&saa716x->gpio_lock, flags); + + return 0; +} + +int saa716x_spi_init(struct saa716x_dev *saa716x) +{ + struct pci_dev *pdev = saa716x->pdev; + struct spi_master *master; + struct saa716x_spi_state *saa716x_spi; + int ret; + + dprintk(SAA716x_DEBUG, 1, "Initializing SAA%02x I2C Core", + saa716x->pdev->device); + + master = spi_alloc_master(&pdev->dev, sizeof (struct saa716x_spi_state)); + if (master == NULL) { + dprintk(SAA716x_ERROR, 1, "ERROR: Cannot allocate SPI Master!"); + return -ENOMEM; + } + + saa716x_spi = spi_master_get_devdata(master); + saa716x_spi->master = master; + saa716x_spi->saa716x = saa716x; + saa716x->saa716x_spi = saa716x_spi; + + master->bus_num = pdev->bus->number; + master->num_chipselect = 1; /* TODO! use config */ + master->cleanup = saa716x_spi_cleanup; + master->setup = saa716x_spi_setup; + master->transfer = saa716x_spi_transfer; + + ret = spi_register_master(master); + if (ret != 0) { + dprintk(SAA716x_ERROR, 1, "ERROR: registering SPI Master!"); + goto err; + } +err: + spi_master_put(master); + return ret; +} +EXPORT_SYMBOL(saa716x_spi_init); + +void saa716x_spi_exit(struct saa716x_dev *saa716x) +{ + struct saa716x_spi_state *saa716x_spi = saa716x->saa716x_spi; + + spi_unregister_master(saa716x_spi->master); + dprintk(SAA716x_DEBUG, 1, "SAA%02x SPI succesfully removed", saa716x->pdev->device); +} +EXPORT_SYMBOL(saa716x_spi_exit); +#endif + diff --git a/drivers/media/common/saa716x/saa716x_spi.h b/drivers/media/common/saa716x/saa716x_spi.h new file mode 100644 index 0000000..0060c22 --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_spi.h @@ -0,0 +1,23 @@ +#ifndef __SAA716x_SPI_H +#define __SAA716x_SPI_H + +struct saa716x_dev; + +struct saa716x_spi_config { + u8 clk_count; + u8 clk_pol:1; + u8 clk_pha:1; + u8 LSB_first:1; +}; + +struct saa716x_spi_state { + struct spi_master *master; + struct saa716x_dev *saa716x; +}; + +extern void saa716x_spi_write(struct saa716x_dev *saa716x, const u8 *data, int length); + +extern int saa716x_spi_init(struct saa716x_dev *saa716x); +extern void saa716x_spi_exit(struct saa716x_dev *saa716x); + +#endif /* __SAA716x_SPI_H */ diff --git a/drivers/media/common/saa716x/saa716x_spi_reg.h b/drivers/media/common/saa716x/saa716x_spi_reg.h new file mode 100644 index 0000000..c51abce --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_spi_reg.h @@ -0,0 +1,27 @@ +#ifndef __SAA716x_SPI_REG_H +#define __SAA716x_SPI_REG_H + +/* -------------- SPI Registers -------------- */ + +#define SPI_CONTROL_REG 0x000 +#define SPI_SERIAL_INTER_ENABLE (0x00000001 << 7) +#define SPI_LSB_FIRST_ENABLE (0x00000001 << 6) +#define SPI_MODE_SELECT (0x00000001 << 5) +#define SPI_CLOCK_POLARITY (0x00000001 << 4) +#define SPI_CLOCK_PHASE (0x00000001 << 3) + +#define SPI_STATUS 0x004 +#define SPI_TRANSFER_FLAG (0x00000001 << 7) +#define SPI_WRITE_COLLISSION (0x00000001 << 6) +#define SPI_READ_OVERRUN (0x00000001 << 5) +#define SPI_MODE_FAULT (0x00000001 << 4) +#define SPI_SLAVE_ABORT (0x00000001 << 3) + +#define SPI_DATA 0x008 +#define SPI_BIDI_DATA (0x000000ff << 0) + +#define SPI_CLOCK_COUNTER 0x00c +#define SPI_CLOCK (0x00000001 << 0) + + +#endif /* __SAA716x_SPI_REG_H */ diff --git a/drivers/media/common/saa716x/saa716x_vip.c b/drivers/media/common/saa716x/saa716x_vip.c new file mode 100644 index 0000000..4cd4c81 --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_vip.c @@ -0,0 +1,23 @@ +#include + +#include "saa716x_mod.h" + +#include "saa716x_vip_reg.h" +#include "saa716x_spi.h" +#include "saa716x_priv.h" + +void saa716x_vipint_disable(struct saa716x_dev *saa716x) +{ + SAA716x_EPWR(VI0, INT_ENABLE, 0); /* disable VI 0 IRQ */ + SAA716x_EPWR(VI1, INT_ENABLE, 0); /* disable VI 1 IRQ */ + SAA716x_EPWR(VI0, INT_CLR_STATUS, 0x3ff); /* clear IRQ */ + SAA716x_EPWR(VI1, INT_CLR_STATUS, 0x3ff); /* clear IRQ */ +} +EXPORT_SYMBOL_GPL(saa716x_vipint_disable); + +void saa716x_vip_disable(struct saa716x_dev *saa716x) +{ + SAA716x_EPWR(VI0, VIP_POWER_DOWN, VI_PWR_DWN); + SAA716x_EPWR(VI1, VIP_POWER_DOWN, VI_PWR_DWN); +} +EXPORT_SYMBOL_GPL(saa716x_vip_disable); diff --git a/drivers/media/common/saa716x/saa716x_vip.h b/drivers/media/common/saa716x/saa716x_vip.h new file mode 100644 index 0000000..55c6a1a --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_vip.h @@ -0,0 +1,9 @@ +#ifndef __SAA716x_VIP_H +#define __SAA716x_VIP_H + +struct saa716x_dev; + +extern void saa716x_vipint_disable(struct saa716x_dev *saa716x); +extern void saa716x_vip_disable(struct saa716x_dev *saa716x); + +#endif /* __SAA716x_VIP_H */ diff --git a/drivers/media/common/saa716x/saa716x_vip_reg.h b/drivers/media/common/saa716x/saa716x_vip_reg.h new file mode 100644 index 0000000..2d773bd --- /dev/null +++ b/drivers/media/common/saa716x/saa716x_vip_reg.h @@ -0,0 +1,127 @@ +#ifndef __SAA716x_VIP_REG_H +#define __SAA716x_VIP_REG_H + +/* -------------- VIP Registers -------------- */ + +#define VI_MODE 0x000 +#define VID_CFEN (0x00000003 << 30) +#define VID_OSM (0x00000001 << 29) +#define VID_FSEQ (0x00000001 << 28) +#define AUX_CFEN (0x00000003 << 26) +#define AUX_OSM (0x00000001 << 25) +#define AUX_FSEQ (0x00000001 << 24) +#define AUX_ANC_DATA (0x00000003 << 22) +#define AUX_ANC_RAW (0x00000001 << 21) +#define RST_ON_ERR (0x00000001 << 17) +#define SOFT_RESET (0x00000001 << 16) +#define IFF_CLAMP (0x00000001 << 14) +#define IFF_MODE (0x00000003 << 12) +#define DFF_CLAMP (0x00000001 << 10) +#define DFF_MODE (0x00000003 << 8) +#define HSP_CLAMP (0x00000001 << 3) +#define HSP_RGB (0x00000001 << 2) +#define HSP_MODE (0x00000003 << 0) + +#define RCRB_CTRL 0x004 +#define RCRB_CFG_ADDR 0x008 +#define RCRB_CFG_EXT_ADDR 0x00c +#define RCRB_IO_ADDR 0x010 +#define RCRB_MEM_LADDR 0x014 +#define RCRB_MEM_UADDR 0x018 +#define RCRB_DATA 0x01c +#define RCRB_MASK 0x020 +#define RCRB_MSG_HDR 0x040 +#define RCRB_MSG_PL0 0x044 +#define RCRB_MSG_PL1 0x048 + +#define ID_MASK0 0x020 +#define VI_ID_MASK_0 (0x000000ff << 8) +#define VI_DATA_ID_0 (0x000000ff << 0) + +#define ID_MASK1 0x024 +#define VI_ID_MASK_1 (0x000000ff << 8) +#define VI_DATA_ID_1 (0x000000ff << 0) + +#define VIP_LINE_THRESH 0x040 +#define VI_LCTHR (0x000007ff << 0) + +#define VIN_FORMAT 0x100 +#define VI_VSRA (0x00000003 << 30) +#define VI_SYNCHD (0x00000001 << 25) +#define VI_DUAL_STREAM (0x00000001 << 24) +#define VI_NHDAUX (0x00000001 << 20) +#define VI_NPAR (0x00000001 << 19) +#define VI_VSEL (0x00000003 << 14) +#define VI_TWOS (0x00000001 << 13) +#define VI_TPG (0x00000001 << 12) +#define VI_FREF (0x00000001 << 10) +#define VI_FTGL (0x00000001 << 9) +#define VI_SF (0x00000001 << 3) +#define VI_FZERO (0x00000001 << 2) +#define VI_REVS (0x00000001 << 1) +#define VI_REHS (0x00000001 << 0) + +#define TC76543210 0x800 +#define TCFEDCBA98 0x804 +#define PHYCFG 0x900 +#define CONFIG 0xfd4 +#define INT_ENABLE_CLR 0xfd8 +#define INT_ENABLE_SET 0xfdc + + +#define INT_STATUS 0xfe0 +#define VI_STAT_FID_AUX (0x00000001 << 31) +#define VI_STAT_FID_VID (0x00000001 << 30) +#define VI_STAT_FID_VPI (0x00000001 << 29) +#define VI_STAT_LINE_COUNT (0x00000fff << 16) +#define VI_STAT_AUX_OVRFLW (0x00000001 << 9) +#define VI_STAT_VID_OVRFLW (0x00000001 << 8) +#define VI_STAT_WIN_SEQBRK (0x00000001 << 7) +#define VI_STAT_FID_SEQBRK (0x00000001 << 6) +#define VI_STAT_LINE_THRESH (0x00000001 << 5) +#define VI_STAT_AUX_WRAP (0x00000001 << 4) +#define VI_STAT_AUX_START_IN (0x00000001 << 3) +#define VI_STAT_AUX_END_OUT (0x00000001 << 2) +#define VI_STAT_VID_START_IN (0x00000001 << 1) +#define VI_STAT_VID_END_OUT (0x00000001 << 0) + +#define INT_ENABLE 0xfe4 +#define VI_ENABLE_AUX_OVRFLW (0x00000001 << 9) +#define VI_ENABLE_VID_OVRFLW (0x00000001 << 8) +#define VI_ENABLE_WIN_SEQBRK (0x00000001 << 7) +#define VI_ENABLE_FID_SEQBRK (0x00000001 << 6) +#define VI_ENABLE_LINE_THRESH (0x00000001 << 5) +#define VI_ENABLE_AUX_WRAP (0x00000001 << 4) +#define VI_ENABLE_AUX_START_IN (0x00000001 << 3) +#define VI_ENABLE_AUX_END_OUT (0x00000001 << 2) +#define VI_ENABLE_VID_START_IN (0x00000001 << 1) +#define VI_ENABLE_VID_END_OUT (0x00000001 << 0) + +#define INT_CLR_STATUS 0xfe8 +#define VI_CLR_STATUS_AUX_OVRFLW (0x00000001 << 9) +#define VI_CLR_STATUS_VID_OVRFLW (0x00000001 << 8) +#define VI_CLR_STATUS_WIN_SEQBRK (0x00000001 << 7) +#define VI_CLR_STATUS_FID_SEQBRK (0x00000001 << 6) +#define VI_CLR_STATUS_LINE_THRESH (0x00000001 << 5) +#define VI_CLR_STATUS_AUX_WRAP (0x00000001 << 4) +#define VI_CLR_STATUS_AUX_START_IN (0x00000001 << 3) +#define VI_CLR_STATUS_AUX_END_OUT (0x00000001 << 2) +#define VI_CLR_STATUS_VID_START_IN (0x00000001 << 1) +#define VI_CLR_STATUS_VID_END_OUT (0x00000001 << 0) + +#define INT_SET_STATUS 0xfec +#define VI_SET_STATUS_AUX_OVRFLW (0x00000001 << 9) +#define VI_SET_STATUS_VID_OVRFLW (0x00000001 << 8) +#define VI_SET_STATUS_WIN_SEQBRK (0x00000001 << 7) +#define VI_SET_STATUS_FID_SEQBRK (0x00000001 << 6) +#define VI_SET_STATUS_LINE_THRESH (0x00000001 << 5) +#define VI_SET_STATUS_AUX_WRAP (0x00000001 << 4) +#define VI_SET_STATUS_AUX_START_IN (0x00000001 << 3) +#define VI_SET_STATUS_AUX_END_OUT (0x00000001 << 2) +#define VI_SET_STATUS_VID_START_IN (0x00000001 << 1) +#define VI_SET_STATUS_VID_END_OUT (0x00000001 << 0) + +#define VIP_POWER_DOWN 0xff4 +#define VI_PWR_DWN (0x00000001 << 31) + +#endif /* __SAA716x_VIP_REG_H */ diff --git a/drivers/media/dvb-frontends/ds3103.h b/drivers/media/dvb-frontends/ds3103.h new file mode 100644 index 0000000..e52740c --- /dev/null +++ b/drivers/media/dvb-frontends/ds3103.h @@ -0,0 +1,47 @@ +/* + Montage Technology DS3103 - DVBS/S2 Demodulator driver + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef DS3103_H +#define DS3103_H + +#include + +struct ds3103_config { + /* the demodulator's i2c address */ + u8 demod_address; + u8 ci_mode; + /* Set device param to start dma */ + int (*set_ts_params)(struct dvb_frontend *fe, int is_punctured); + /* Hook for Lock LED */ + void (*set_lock_led)(struct dvb_frontend *fe, int offon); +}; + +#if defined(CONFIG_DVB_DS3103) || \ + (defined(CONFIG_DVB_DS3103_MODULE) && defined(MODULE)) +extern struct dvb_frontend *ds3103_attach(const struct ds3103_config *config, + struct i2c_adapter *i2c); +#else +static inline +struct dvb_frontend *ds3103_attach(const struct ds3103_config *config, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_DS3103 */ +#endif /* DS3103_H */ diff --git a/drivers/media/dvb-frontends/ts2022.h b/drivers/media/dvb-frontends/ts2022.h new file mode 100644 index 0000000..c894edb --- /dev/null +++ b/drivers/media/dvb-frontends/ts2022.h @@ -0,0 +1,51 @@ + /* + Driver for Montage TS2022 DVBS/S2 Silicon tuner + + Copyright (C) 2012 Tomazzo Muzumici + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + */ + +#ifndef __DVB_TS2022_H__ +#define __DVB_TS2022_H__ + +#include +#include "dvb_frontend.h" + +/** + * Attach a ts2022 tuner to the supplied frontend structure. + * + * @param fe Frontend to attach to. + * @param addr i2c address of the tuner. + * @param i2c i2c adapter to use. + * @return FE pointer on success, NULL on failure. + */ +#if defined(CONFIG_DVB_TS2022) || (defined(CONFIG_DVB_TS2022_MODULE) \ + && defined(MODULE)) +extern struct dvb_frontend *ts2022_attach(struct dvb_frontend *fe, int addr, + struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend *ts2022_attach(struct dvb_frontend *fe, + int addr, + struct i2c_adapter *i2c) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_TS2022 */ + +#endif /* __DVB_TS2022_H__ */ diff --git a/include/uapi/linux/dvb/osd.h b/include/uapi/linux/dvb/osd.h index 880e684..edd728c 100644 --- a/include/uapi/linux/dvb/osd.h +++ b/include/uapi/linux/dvb/osd.h @@ -141,4 +141,20 @@ typedef struct osd_cap_s { #define OSD_SEND_CMD _IOW('o', 160, osd_cmd_t) #define OSD_GET_CAPABILITY _IOR('o', 161, osd_cap_t) +typedef struct osd_raw_cmd_s { + const void __user *cmd_data; + int cmd_len; + void __user *result_data; + int result_len; +} osd_raw_cmd_t; + +typedef struct osd_raw_data_s { + const void __user *data_buffer; + int data_length; + int data_handle; +} osd_raw_data_t; + +#define OSD_RAW_CMD _IOWR('o', 162, osd_raw_cmd_t) +#define OSD_RAW_DATA _IOWR('o', 163, osd_raw_data_t) + #endif