466 lines
10 KiB
C
466 lines
10 KiB
C
/*
|
|
* GPIO code
|
|
*
|
|
* $Header$
|
|
*/
|
|
|
|
|
|
#include <unistd.h> /*usleep*/
|
|
|
|
#include "minihwc.h"
|
|
#ifdef __WATCOMC__
|
|
#include <i86.h>
|
|
#include "h3cini~1.h"
|
|
#define usleep(x) delay((x) / 1000)
|
|
#else
|
|
#include "h3cinitdd.h"
|
|
#endif
|
|
|
|
|
|
|
|
#define USEC (1000)
|
|
#define DTIME (5*USEC)
|
|
#define MSEC (1000000)
|
|
#define D60HZ (166*MSEC)
|
|
#define DELAY(x) usleep(x)
|
|
#define CLOCK_STRETCH (1000)
|
|
#define NUM_RETRY (5)
|
|
|
|
#define BUILD_BYTE(data, mask, position) ((unsigned char)((data & mask)<<position))
|
|
|
|
#define ABS(A, B) ((A) < (B) ? (B) - (A) : (A) - (B))
|
|
#define MHz(A) ((A) * 1000000)
|
|
#define kHz(A) ((A) * 1000)
|
|
|
|
typedef struct {
|
|
unsigned long dwBus; /* Bus */
|
|
unsigned long dwDevFunc;/* DevNode */
|
|
unsigned long RN; /* Register Number */
|
|
unsigned long dInMask; /* Data Mask */
|
|
unsigned long dOutMask; /* Data Mask */
|
|
unsigned long dInShift; /* Data Shift */
|
|
unsigned long dOutShift;/* Data Shift */
|
|
} PCI_BIT;
|
|
|
|
typedef struct {
|
|
PCI_BIT Data;
|
|
PCI_BIT Clk;
|
|
PCI_BIT Strobe;
|
|
PCI_BIT HiVoltage;
|
|
} GPIOMASK;
|
|
|
|
|
|
|
|
static unsigned long pci_read_cfg (unsigned long bus,
|
|
unsigned long dwDevFunc,
|
|
unsigned long offset)
|
|
{
|
|
FxU32 data, result;
|
|
|
|
PciRegister reg;
|
|
reg.regAddress = offset;
|
|
reg.sizeInBytes = 4;
|
|
|
|
result = pciGetConfigData/*Raw*/(reg, ((dwDevFunc & 7) << 13) | (bus << 5) | (dwDevFunc & 0x1f), &data);
|
|
/* --------function------- ----bus--- ------device------ */
|
|
|
|
return data;
|
|
}
|
|
|
|
static unsigned long pci_write_cfg (unsigned long bus,
|
|
unsigned long dwDevFunc,
|
|
unsigned long offset,
|
|
unsigned long value)
|
|
{
|
|
PciRegister reg;
|
|
reg.regAddress = offset;
|
|
reg.sizeInBytes = 4;
|
|
|
|
return pciSetConfigData/*Raw*/(reg, ((dwDevFunc & 7) << 13) | (bus << 5) | (dwDevFunc & 0x1f), &value);
|
|
/* --------function------- ----bus--- ------device------ */
|
|
}
|
|
|
|
|
|
|
|
/* Desc: scan for GPIO
|
|
*
|
|
* In : device+vendor ID, bus number to match
|
|
* Out : 0 for failure
|
|
*
|
|
* Note:
|
|
*/
|
|
int gpio_find_device (unsigned long dwDevVenID,
|
|
unsigned long dwBus,
|
|
unsigned long *pdwBus,
|
|
unsigned long *pdwDevFunc)
|
|
{
|
|
for (*pdwBus = 0; *pdwBus < 256; *pdwBus += 1) {
|
|
for (*pdwDevFunc = 0; *pdwDevFunc < 0x100; *pdwDevFunc += 0x08) {
|
|
if ((dwDevVenID == pci_read_cfg(*pdwBus, *pdwDevFunc, 0x0)) &&
|
|
(dwBus == (pci_read_cfg(*pdwBus, *pdwDevFunc, 0x19) & 0xFF))) {
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/* Desc: init GPIO port
|
|
*
|
|
* In :
|
|
* Out :
|
|
*
|
|
* Note: 0 for failure
|
|
*/
|
|
int gpio_init (GPIOMASK *pGPIOMask, unsigned long dwNapalmBus)
|
|
{
|
|
static int isGPIOInit = 0;
|
|
|
|
unsigned long dwBus;
|
|
unsigned long dwDevFunc;
|
|
unsigned long dwData;
|
|
|
|
if (0 == isGPIOInit) {
|
|
if (gpio_find_device(0x00213388, dwNapalmBus, &dwBus, &dwDevFunc)) {
|
|
isGPIOInit = 1;
|
|
pGPIOMask->Data.dwBus = pGPIOMask->Clk.dwBus = pGPIOMask->Strobe.dwBus = dwBus;
|
|
pGPIOMask->Data.dwDevFunc = pGPIOMask->Clk.dwDevFunc = pGPIOMask->Strobe.dwDevFunc = dwDevFunc;
|
|
|
|
pGPIOMask->Data.RN = 0xC4;
|
|
pGPIOMask->Data.dInMask = 0x0100;
|
|
pGPIOMask->Data.dInShift = 0x08;
|
|
pGPIOMask->Data.dOutMask = 0x0400;
|
|
pGPIOMask->Data.dOutShift = 0x0A;
|
|
|
|
pGPIOMask->Clk.RN = 0xC4;
|
|
pGPIOMask->Clk.dInMask = 0x010000;
|
|
pGPIOMask->Clk.dInShift = 0x10;
|
|
pGPIOMask->Clk.dOutMask = 0x040000;
|
|
pGPIOMask->Clk.dOutShift = 0x12;
|
|
|
|
pGPIOMask->Strobe.RN = 0xC4;
|
|
pGPIOMask->Strobe.dInMask = 0x1000;
|
|
pGPIOMask->Strobe.dInShift = 0x0C;
|
|
pGPIOMask->Strobe.dOutMask = 0x4000;
|
|
pGPIOMask->Strobe.dOutShift = 0x0E;
|
|
|
|
pGPIOMask->HiVoltage.RN = 0xC4;
|
|
pGPIOMask->HiVoltage.dInMask = 0x100000;
|
|
pGPIOMask->HiVoltage.dInShift = 0x14;
|
|
pGPIOMask->HiVoltage.dOutMask = 0x400000;
|
|
pGPIOMask->HiVoltage.dOutShift = 0x16;
|
|
|
|
/* Enable all GPIO as Output */
|
|
dwData = pci_read_cfg(dwBus, dwDevFunc, 0xC4);
|
|
dwData &= 0xFF0000FF;
|
|
/* C7C6C5C4 */
|
|
dwData |= 0x00222200;
|
|
pci_write_cfg(dwBus, dwDevFunc, 0xC4, dwData);
|
|
}
|
|
} else {
|
|
dwData = pci_read_cfg(pGPIOMask->Data.dwBus, pGPIOMask->Data.dwDevFunc, 0xC4);
|
|
dwData &= 0xFF0000FF;
|
|
/* C7C6C5C4 */
|
|
dwData |= 0x00222200;
|
|
pci_write_cfg(pGPIOMask->Data.dwBus, pGPIOMask->Data.dwDevFunc, 0xC4, dwData);
|
|
}
|
|
|
|
return isGPIOInit;
|
|
}
|
|
|
|
|
|
|
|
/* Desc: read a dword
|
|
*
|
|
* In :
|
|
* Out :
|
|
*
|
|
* Note: dword
|
|
*/
|
|
unsigned long gpio_get (PCI_BIT *pPCI_BIT)
|
|
{
|
|
return pci_read_cfg(pPCI_BIT->dwBus, pPCI_BIT->dwDevFunc, pPCI_BIT->RN);
|
|
}
|
|
|
|
|
|
|
|
/* Desc: read a bit
|
|
*
|
|
* In :
|
|
* Out : bit
|
|
*
|
|
* Note:
|
|
*/
|
|
unsigned long gpio_get_bit (PCI_BIT *pPCI_BIT)
|
|
{
|
|
unsigned long bData;
|
|
bData = pci_read_cfg(pPCI_BIT->dwBus, pPCI_BIT->dwDevFunc, pPCI_BIT->RN);
|
|
return (bData & pPCI_BIT->dInMask) >> pPCI_BIT->dInShift;
|
|
}
|
|
|
|
|
|
|
|
/* Desc: write a bit
|
|
*
|
|
* In :
|
|
* Out :
|
|
*
|
|
* Note:
|
|
*/
|
|
unsigned long gpio_set_bit (PCI_BIT *pPCI_BIT, unsigned long dwValue)
|
|
{
|
|
unsigned long dwReg;
|
|
|
|
dwReg = gpio_get(pPCI_BIT);
|
|
dwReg = dwReg & ~pPCI_BIT->dOutMask;
|
|
dwReg |= ((dwValue & 0x01) << pPCI_BIT->dOutShift);
|
|
|
|
return pci_write_cfg(pPCI_BIT->dwBus, pPCI_BIT->dwDevFunc, pPCI_BIT->RN, dwReg);
|
|
}
|
|
|
|
|
|
|
|
/* Desc: read the clock
|
|
*
|
|
* In :
|
|
* Out :
|
|
*
|
|
* Note:
|
|
*/
|
|
int gpio_read_scl (GPIOMASK *pGPIOMask)
|
|
{
|
|
return gpio_get_bit(&pGPIOMask->Clk);
|
|
}
|
|
|
|
|
|
|
|
/* Desc: set the Clock to bit
|
|
*
|
|
* In :
|
|
* Out :
|
|
*
|
|
* Note:
|
|
*/
|
|
void gpio_scl (GPIOMASK *pGPIOMask, unsigned long bit)
|
|
{
|
|
int nCount = 0;
|
|
|
|
DELAY(DTIME);
|
|
gpio_set_bit(&pGPIOMask->Clk, bit);
|
|
DELAY(DTIME);
|
|
|
|
if (bit) {
|
|
while (!gpio_read_scl(pGPIOMask) && (nCount++ < CLOCK_STRETCH)) {
|
|
DELAY(DTIME);
|
|
}
|
|
|
|
if (nCount++ >= CLOCK_STRETCH) {
|
|
/*fprintf(stderr, "Slave did not respond %s %d\n", __FILE__, __LINE__);*/
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* Desc: set the Data to bit.
|
|
*
|
|
* In :
|
|
* Out :
|
|
*
|
|
* Note:
|
|
*/
|
|
void gpio_sda (GPIOMASK *pGPIOMask, unsigned long bit)
|
|
{
|
|
DELAY(DTIME);
|
|
bit = bit >> 7;
|
|
gpio_set_bit(&pGPIOMask->Data, bit);
|
|
DELAY(DTIME);
|
|
}
|
|
|
|
|
|
|
|
/* Desc: send the byte data
|
|
*
|
|
* In :
|
|
* Out :
|
|
*
|
|
* Note:
|
|
*/
|
|
int gpio_send_byte (GPIOMASK *pGPIOMask,
|
|
unsigned char b1,
|
|
unsigned char b2,
|
|
unsigned char b3)
|
|
{
|
|
int i;
|
|
int nReturn = 0;
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
gpio_sda(pGPIOMask, (b1 << i) & 0x80);
|
|
gpio_scl(pGPIOMask, 1);
|
|
if (gpio_read_scl(pGPIOMask) == 0) {
|
|
/*fprintf(stderr, "nc\n");*/
|
|
}
|
|
gpio_scl(pGPIOMask, 0);
|
|
}
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
gpio_sda(pGPIOMask, (b2 << i) & 0x80);
|
|
gpio_scl(pGPIOMask, 1);
|
|
if (gpio_read_scl(pGPIOMask) == 0) {
|
|
/*fprintf(stderr, "nc\n");*/
|
|
}
|
|
gpio_scl(pGPIOMask, 0);
|
|
}
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
gpio_sda(pGPIOMask, (b3 << i) & 0x80);
|
|
gpio_scl(pGPIOMask, 1);
|
|
if (gpio_read_scl(pGPIOMask) == 0) {
|
|
/*fprintf(stderr, "nc\n");*/
|
|
}
|
|
gpio_scl(pGPIOMask, 0);
|
|
}
|
|
|
|
/* Strobe to make it happen */
|
|
DELAY(DTIME);
|
|
gpio_set_bit(&pGPIOMask->Strobe, 1);
|
|
DELAY(DTIME);
|
|
|
|
DELAY(DTIME);
|
|
gpio_set_bit(&pGPIOMask->Strobe, 0);
|
|
DELAY(DTIME);
|
|
|
|
return nReturn;
|
|
}
|
|
|
|
|
|
|
|
/* Desc: build and send clock
|
|
*
|
|
* In :
|
|
* Out :
|
|
*
|
|
* Note:
|
|
*/
|
|
unsigned long gpio_output_clock (hwcBoardInfo *bInfo,
|
|
unsigned long c,
|
|
unsigned long ttl,
|
|
unsigned long f,
|
|
unsigned long s,
|
|
unsigned long v,
|
|
unsigned long r)
|
|
{
|
|
static GPIOMASK GpioMask;
|
|
|
|
unsigned char b1, b2, b3;
|
|
|
|
b1 = BUILD_BYTE(c, 3, 6);
|
|
b1 |= BUILD_BYTE(ttl, 1, 5);
|
|
b1 |= BUILD_BYTE(f, 3, 3);
|
|
b1 |= BUILD_BYTE(s, 7, 0);
|
|
|
|
b2 = (unsigned char)((v & 0x1Fe) >> 1);
|
|
|
|
b3 = BUILD_BYTE(v, 1, 7);
|
|
b3 |= BUILD_BYTE(r, 0x7F, 0);
|
|
|
|
/* Use the bus number embedded at deviceNum[5:12]. */
|
|
if (gpio_init(&GpioMask, (bInfo->deviceNum >> 5) & 0xFF))
|
|
gpio_send_byte(&GpioMask, b1, b2, b3);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/* Desc:
|
|
*
|
|
* In :
|
|
* Out : 0 for failure
|
|
*
|
|
* Note:
|
|
*/
|
|
unsigned long gpio_6k_clock (hwcBoardInfo *bInfo)
|
|
{
|
|
static unsigned long OD[] = {2, 3, 4, 5, 6, 7, 8, 10};
|
|
static unsigned long S2S1S0[] = {15, 15, 1, 6, 3, 4, 7, 5, 2, 15, 0};
|
|
|
|
double d_clk1;
|
|
double clk1;
|
|
double d_diff;
|
|
double d_partial;
|
|
unsigned long rdw;
|
|
unsigned long vdw;
|
|
unsigned long od;
|
|
unsigned long i;
|
|
unsigned long b_rdw;
|
|
unsigned long b_vdw;
|
|
unsigned long b_od;
|
|
unsigned long b_i;
|
|
unsigned long bFound;
|
|
unsigned long ic;
|
|
unsigned long pixelclock;
|
|
unsigned long n;
|
|
unsigned long m;
|
|
unsigned long k;
|
|
unsigned long kpow;
|
|
|
|
/* Get the Clock */
|
|
FxU32 regBase = bInfo->regInfo.ioPortBase;
|
|
pixelclock = IGET32(pllCtrl0);
|
|
n = ((pixelclock & 0xFF00) >> 8)+2;
|
|
m = ((pixelclock & 0xFC) >> 2)+2;
|
|
k = pixelclock & 0x03;
|
|
|
|
kpow = 1;
|
|
for (i = 0; i < k; i++) {
|
|
kpow <<= 1;
|
|
}
|
|
|
|
/* This should work to 4 GigaHertz */
|
|
ic = 14318180 * n / m / kpow;
|
|
ic >>= 2;
|
|
|
|
d_diff = MHz(500.0);
|
|
i = 0;
|
|
bFound = 0;
|
|
for (i = 0; i < sizeof(OD)/sizeof(unsigned long); i++) {
|
|
od = OD[i];
|
|
for (rdw = 1; rdw < 128; rdw++) {
|
|
for (vdw = 4; vdw < 512; vdw++) {
|
|
clk1 = 14318180.0*2.0*((double)vdw+8.0)/(((double)rdw+2.0)*(double)od);
|
|
if (ABS(clk1, (double)ic) < d_diff) {
|
|
/* Some constraints on vdw & rdw
|
|
* 55 Mhz < 14318180 * 2* (vdw+8)/(rdw + 2) < 400 Mhz
|
|
*/
|
|
d_partial = 14318180.0*2.0*((double)vdw+8.0)/((double)rdw+2.0);
|
|
if ((d_partial > MHz(55)) && (d_partial < MHz(400))) {
|
|
/* Another constraints
|
|
* 200 kHz < 14318180/(rdw+2)
|
|
*/
|
|
if (14318180/(rdw+2) > kHz(200)) {
|
|
d_diff = ABS(clk1, (double)ic);
|
|
bFound = 1;
|
|
b_rdw = rdw;
|
|
b_vdw = vdw;
|
|
b_od = od;
|
|
b_i = i;
|
|
d_clk1 = clk1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bFound) {
|
|
gpio_output_clock(bInfo, 0x0, 0x1, 0x0, S2S1S0[b_od], b_vdw, b_rdw);
|
|
return ic;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|