This is the mail archive of the ecos-discuss@sources.redhat.com mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

eCos Device driver confusion.


   I'm attempting to write a Device Driver for a Universe PCI->VME bridge
on eCos. Unfortunately I keep running into walls and very bizzare
problems. I'm very confused, it seems as if when I find my device the
registers are already assigned values. For instance, there is a
"PCI_BS" register that I print out using:
cyg_pci_read_config_uint32(uni_pci_dev_id, PCI_BS, &ba);
printf("%08X\n", ba);

Output:
FFFE0000

  Keep in mind that I've rebooted my target system, and just located the
apropriate PCI device, so I haven't touched any of the registers yet.

  According to the manual for this PCI device the PCI_BS is decribed as
having a reset state value of "0." And it's technically the first
register I'm supposed to write to.
"Since all Memory and I/O accesses are specified in relation to the Base
Address, a write must occur to this register before any Universe registers
can be accessed through PCI memory or I/O space. This initial write can be
performed with a PCI configuration transaction or a VMEbus register
access."

  And, this was true when I was working on Linux. For some reason on eCos
it has a value already assigned to it. The strange thing is, this
original value works, I can read from the configuration space and get
apropriate values out. Now, the problem is writting to this already
existing register space. I need to map VME bus address ranges to an
address range in hardware memory. I'm not exactly certain for one how to
figure out what hardware address ranges are useable on my system. When I
try to write to these registers through the memory map, it just doesn't
work.

// Setup the Mapping in the Universe
OUTL(baseaddr + aBS[image],pci);
val = INL(baseaddr + aBS[image]);
printf("%08X, %08X\n", pci, val);
Outputs: 0F000000, 0E000000

OUTL looks like:
static inline void OUTL(cyg_uint32 value, cyg_uint32 io_address)
{ cyg_uint32* myLong = (cyg_uint32*)io_address; *myLong = value; }

So. I can read from this region just fine, but I can't write to it
apparently. I tried writting directly into the registers instead using:

cyg_pci_write_config_uint32(uni_pci_dev_id, aBS[image], pci);
cyg_pci_read_config_uint32(uni_pci_dev_id, aBS[image], &val);
printf("%08X, %08X\n", pci, val);

Outputs:
Outputs: 0F000000, 02000000

But, it has a Bus error, and the Universe chip stops responding. All reads
to the memory mapped registers become FFFFFFFF.

Here is my full init function:
int init(void)
{
  int i;
  bool deviceFound = false;
  cyg_pci_init(); //Initialize PCI.

  //int x, result;
  unsigned int temp, ba, status;
  //char vstr[80];


  if (cyg_pci_find_next(CYG_PCI_NULL_DEVID, &uni_pci_dev_id))
  {
    do
    {
      cyg_pci_get_device_info(uni_pci_dev_id, &uni_pci_dev);
      if(uni_pci_dev.vendor == 0x10E3 && uni_pci_dev.device == 0x0000)
      {
	deviceFound = true;
	printf("Universe device found.");

	// Lets turn Latency off
	cyg_pci_write_config_uint32(uni_pci_dev_id, PCI_MISC0, 0);

	// Display PCI Registers
	cyg_pci_read_config_uint32(uni_pci_dev_id, PCI_CSR, &status);
	printf("  Vendor = %04X  Device = %04X  Status = %08X\n",
	       uni_pci_dev.vendor,uni_pci_dev.device,status);
	///printf("  Class = %08X\n",uni_pci_dev.class);

	cyg_pci_read_config_uint32(uni_pci_dev_id, PCI_MISC0, &temp);
	printf("  Misc0 = %08X\n",temp);


	// Setup Universe Config Space
	// This is a 4k wide memory area that need to be mapped into the kernel
	// virtual memory space so we can access it.

	cyg_pci_write_config_uint32(uni_pci_dev_id, PCI_BS,
0xFFFC0000);//CONFIG_REG_SPACE);
	cyg_pci_read_config_uint32(uni_pci_dev_id, PCI_BS, &ba);
	printf("%08X\n", ba);

       	//Configure the device?
	cyg_pci_configure_device(&uni_pci_dev);

	// Check to see if the Mapping Worked out
	baseaddr = ba;
	temp = INL(baseaddr);
	printf("Read via mapping, PCI_ID = %08X\nBaseaddr=%08X,%08X\n",temp,
INL(baseaddr+PCI_BS), ba);

	if (temp != 0x000010E3)
	{
	    printf("Error: Universe Chip Failed to Return PCI_ID in Memory Map.\n");
	    return -1;
	}

	// OK, Every this is ok so lets turn off the windows
	OUTL(baseaddr+LSI0_CTL,0x00800000);
	OUTL(baseaddr+LSI1_CTL,0x00800000);
	OUTL(baseaddr+LSI2_CTL,0x00800000);
	OUTL(baseaddr+LSI3_CTL,0x00800000);

	// Write to Misc Register
	// Set VME Bus Time-out
	//   Arbitration Mode
	//   DTACK Enable
	OUTL(baseaddr+MISC_CTL, 0x15060000);


	if (cyg_pci_translate_interrupt(&uni_pci_dev, &irq))
	  diag_printf(" Wired to HAL vector %d\n", irq);

	//	cyg_drv_interrupt_create(irq, 0,

	// Lets turn off interrupts
	//writel(0x00000000,baseaddr+LINT_EN);   // Disable interrupts in the
Universe first
	//writel(0x0000FFFF,baseaddr+LINT_STAT); // Clear Any Pending Interrupts

	int tstirq = 0;
        cyg_pci_read_config_uint32(uni_pci_dev_id, PCI_INTERRUPT_LINE,
&tstirq);
	printf("IRQ found: %08X\n", tstirq);
	/*
	irq &= 0x000000FF;                    // Only a byte in size
	result = request_irq(irq, irq_handler, SA_INTERRUPT, "VMEBus (ca91c042)",
NULL);

	if (result)
	{
	  printf("  ca91c042: can't get assigned pci irq vector %02X\n", irq);
	}
	else
	{
	  writel(0x0000, baseaddr+LINT_MAP0);    // Map all ints to 0
	  writel(0x0000, baseaddr+LINT_MAP1);    // Map all ints to 0
	}*/
	break;
      }
    } while (cyg_pci_find_next(uni_pci_dev_id, &uni_pci_dev_id));
    if(!deviceFound)
    {
      printf("Error: Universe device not found on PCI Bus.\n");
      return -1;
    }
  }

  // Setup the DMA Timer

  //init_timer(&DMA_timer);
  //DMA_timer.function = DMA_status;

  // Enable DMA Interrupts

  //writel(0x0700, baseaddr+LINT_EN);

  return 0;
}

And the mapvme function:
CYG_PCI_ADDRESS32 cygmapvme(CYG_PCI_ADDRESS32 pci,CYG_PCI_ADDRESS32 vme,
unsigned int size, int image, int ctl)
{
  unsigned int to;
  int val;

  if ((image >=0) && (image <=3))
  {
      to = vme-pci;
      // Setup the Mapping in the Universe
      OUTL(baseaddr + aBS[image],pci);
      val = INL(baseaddr + aBS[image]);
      printf("%08X, %08X\n", pci, val);

      OUTL(baseaddr + aBD[image],pci + size);
      OUTL(baseaddr + aTO[image],to);
      OUTL(baseaddr + aCTL[image],ctl | ctrl_en);

      puts("Universe mapped.");

      return pci;        // Everything went ok, return the address pointer
  }
  puts("Universe failed to map.");
  return 0;
}

So, the questions here in summary are:
1.) Why is by PCI_BS register already configured?
2.) Is there a good tutorial available for the differences between
writting Linux device drivers and eCos device drivers (or any tutorial at
all for writting eCos device drivers?)
3.) How do I find out what hardware address ranges are unused and avaiable
for my device driver?

Thanks in advance for any help!

-Jason Thomas.

-- 
Before posting, please read the FAQ: http://ecos.sourceware.org/fom/ecos
and search the list archive: http://ecos.sourceware.org/ml/ecos-discuss


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]