mirror of https://gitee.com/openkylin/linux.git
236 lines
5.7 KiB
C
236 lines
5.7 KiB
C
|
/*
|
||
|
Mantis PCI bridge driver
|
||
|
|
||
|
Copyright (C) Manu Abraham (abraham.manu@gmail.com)
|
||
|
|
||
|
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.
|
||
|
*/
|
||
|
|
||
|
#include "mantis_common.h"
|
||
|
#include "mantis_core.h"
|
||
|
#include "mantis_vp1033.h"
|
||
|
#include "mantis_vp1034.h"
|
||
|
#include "mantis_vp1041.h"
|
||
|
#include "mantis_vp2033.h"
|
||
|
#include "mantis_vp2040.h"
|
||
|
#include "mantis_vp3030.h"
|
||
|
|
||
|
static int read_eeprom_byte(struct mantis_pci *mantis, u8 *data, u8 length)
|
||
|
{
|
||
|
int err;
|
||
|
struct i2c_msg msg[] = {
|
||
|
{
|
||
|
.addr = 0x50,
|
||
|
.flags = 0,
|
||
|
.buf = data,
|
||
|
.len = 1
|
||
|
}, {
|
||
|
.addr = 0x50,
|
||
|
.flags = I2C_M_RD,
|
||
|
.buf = data,
|
||
|
.len = length
|
||
|
},
|
||
|
};
|
||
|
|
||
|
err = i2c_transfer(&mantis->adapter, msg, 2);
|
||
|
if (err < 0) {
|
||
|
dprintk(verbose, MANTIS_ERROR, 1,
|
||
|
"ERROR: i2c read: < err=%i d0=0x%02x d1=0x%02x >",
|
||
|
err, data[0], data[1]);
|
||
|
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int write_eeprom_byte(struct mantis_pci *mantis, u8 *data, u8 length)
|
||
|
{
|
||
|
int err;
|
||
|
|
||
|
struct i2c_msg msg = {
|
||
|
.addr = 0x50,
|
||
|
.flags = 0,
|
||
|
.buf = data,
|
||
|
.len = length
|
||
|
};
|
||
|
|
||
|
err = i2c_transfer(&mantis->adapter, &msg, 1);
|
||
|
if (err < 0) {
|
||
|
dprintk(verbose, MANTIS_ERROR, 1,
|
||
|
"ERROR: i2c write: < err=%i length=0x%02x d0=0x%02x, d1=0x%02x >",
|
||
|
err, length, data[0], data[1]);
|
||
|
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int get_mac_address(struct mantis_pci *mantis)
|
||
|
{
|
||
|
int err;
|
||
|
|
||
|
mantis->mac_address[0] = 0x08;
|
||
|
err = read_eeprom_byte(mantis, &mantis->mac_address[0], 6);
|
||
|
if (err < 0) {
|
||
|
dprintk(verbose, MANTIS_ERROR, 1, "Mantis EEPROM read error");
|
||
|
|
||
|
return err;
|
||
|
}
|
||
|
dprintk(verbose, MANTIS_ERROR, 0,
|
||
|
" MAC Address=[%pM]\n", mantis->mac_address);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
#define MANTIS_MODEL_UNKNOWN "UNKNOWN"
|
||
|
#define MANTIS_DEV_UNKNOWN "UNKNOWN"
|
||
|
|
||
|
struct mantis_hwconfig unknown_device = {
|
||
|
.model_name = MANTIS_MODEL_UNKNOWN,
|
||
|
.dev_type = MANTIS_DEV_UNKNOWN,
|
||
|
};
|
||
|
|
||
|
static void mantis_load_config(struct mantis_pci *mantis)
|
||
|
{
|
||
|
switch (mantis->subsystem_device) {
|
||
|
case MANTIS_VP_1033_DVB_S: /* VP-1033 */
|
||
|
mantis->hwconfig = &vp1033_mantis_config;
|
||
|
break;
|
||
|
case MANTIS_VP_1034_DVB_S: /* VP-1034 */
|
||
|
mantis->hwconfig = &vp1034_mantis_config;
|
||
|
break;
|
||
|
case MANTIS_VP_1041_DVB_S2: /* VP-1041 */
|
||
|
case TECHNISAT_SKYSTAR_HD2:
|
||
|
mantis->hwconfig = &vp1041_mantis_config;
|
||
|
break;
|
||
|
case MANTIS_VP_2033_DVB_C: /* VP-2033 */
|
||
|
mantis->hwconfig = &vp2033_mantis_config;
|
||
|
break;
|
||
|
case MANTIS_VP_2040_DVB_C: /* VP-2040 */
|
||
|
case CINERGY_C: /* VP-2040 clone */
|
||
|
case TECHNISAT_CABLESTAR_HD2:
|
||
|
mantis->hwconfig = &vp2040_mantis_config;
|
||
|
break;
|
||
|
case MANTIS_VP_3030_DVB_T: /* VP-3030 */
|
||
|
mantis->hwconfig = &vp3030_mantis_config;
|
||
|
break;
|
||
|
default:
|
||
|
mantis->hwconfig = &unknown_device;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int mantis_core_init(struct mantis_pci *mantis)
|
||
|
{
|
||
|
int err = 0;
|
||
|
|
||
|
mantis_load_config(mantis);
|
||
|
dprintk(verbose, MANTIS_ERROR, 0, "found a %s PCI %s device on (%02x:%02x.%x),\n",
|
||
|
mantis->hwconfig->model_name, mantis->hwconfig->dev_type,
|
||
|
mantis->pdev->bus->number, PCI_SLOT(mantis->pdev->devfn), PCI_FUNC(mantis->pdev->devfn));
|
||
|
dprintk(verbose, MANTIS_ERROR, 0, " Mantis Rev %d [%04x:%04x], ",
|
||
|
mantis->revision,
|
||
|
mantis->subsystem_vendor, mantis->subsystem_device);
|
||
|
dprintk(verbose, MANTIS_ERROR, 0,
|
||
|
"irq: %d, latency: %d\n memory: 0x%lx, mmio: 0x%p\n",
|
||
|
mantis->pdev->irq, mantis->latency,
|
||
|
mantis->mantis_addr, mantis->mantis_mmio);
|
||
|
|
||
|
err = mantis_i2c_init(mantis);
|
||
|
if (err < 0) {
|
||
|
dprintk(verbose, MANTIS_ERROR, 1, "Mantis I2C init failed");
|
||
|
return err;
|
||
|
}
|
||
|
err = get_mac_address(mantis);
|
||
|
if (err < 0) {
|
||
|
dprintk(verbose, MANTIS_ERROR, 1, "get MAC address failed");
|
||
|
return err;
|
||
|
}
|
||
|
err = mantis_dma_init(mantis);
|
||
|
if (err < 0) {
|
||
|
dprintk(verbose, MANTIS_ERROR, 1, "Mantis DMA init failed");
|
||
|
return err;
|
||
|
}
|
||
|
err = mantis_dvb_init(mantis);
|
||
|
if (err < 0) {
|
||
|
dprintk(verbose, MANTIS_DEBUG, 1, "Mantis DVB init failed");
|
||
|
return err;
|
||
|
}
|
||
|
err = mantis_uart_init(mantis);
|
||
|
if (err < 0) {
|
||
|
dprintk(verbose, MANTIS_DEBUG, 1, "Mantis UART init failed");
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int mantis_core_exit(struct mantis_pci *mantis)
|
||
|
{
|
||
|
mantis_dma_stop(mantis);
|
||
|
dprintk(verbose, MANTIS_ERROR, 1, "DMA engine stopping");
|
||
|
|
||
|
mantis_uart_exit(mantis);
|
||
|
dprintk(verbose, MANTIS_ERROR, 1, "UART exit failed");
|
||
|
|
||
|
if (mantis_dma_exit(mantis) < 0)
|
||
|
dprintk(verbose, MANTIS_ERROR, 1, "DMA exit failed");
|
||
|
if (mantis_dvb_exit(mantis) < 0)
|
||
|
dprintk(verbose, MANTIS_ERROR, 1, "DVB exit failed");
|
||
|
if (mantis_i2c_exit(mantis) < 0)
|
||
|
dprintk(verbose, MANTIS_ERROR, 1, "I2C adapter delete.. failed");
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* Turn the given bit on or off. */
|
||
|
void gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value)
|
||
|
{
|
||
|
u32 cur;
|
||
|
|
||
|
cur = mmread(MANTIS_GPIF_ADDR);
|
||
|
if (value)
|
||
|
mantis->gpio_status = cur | (1 << bitpos);
|
||
|
else
|
||
|
mantis->gpio_status = cur & (~(1 << bitpos));
|
||
|
|
||
|
mmwrite(mantis->gpio_status, MANTIS_GPIF_ADDR);
|
||
|
mmwrite(0x00, MANTIS_GPIF_DOUT);
|
||
|
udelay(100);
|
||
|
}
|
||
|
|
||
|
/* direction = 0 , no CI passthrough ; 1 , CI passthrough */
|
||
|
void mantis_set_direction(struct mantis_pci *mantis, int direction)
|
||
|
{
|
||
|
u32 reg;
|
||
|
|
||
|
reg = mmread(0x28);
|
||
|
dprintk(verbose, MANTIS_DEBUG, 1, "TS direction setup");
|
||
|
if (direction == 0x01) {
|
||
|
/* to CI */
|
||
|
reg |= 0x04;
|
||
|
mmwrite(reg, 0x28);
|
||
|
reg &= 0xff - 0x04;
|
||
|
mmwrite(reg, 0x28);
|
||
|
} else {
|
||
|
reg &= 0xff - 0x04;
|
||
|
mmwrite(reg, 0x28);
|
||
|
reg |= 0x04;
|
||
|
mmwrite(reg, 0x28);
|
||
|
}
|
||
|
}
|