Subversion Repositories HelenOS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. #include <unistd.h>
  2. #include <ddi.h>
  3. #include <libarch/ddi.h>
  4. #include <stdio.h>
  5.  
  6. #include "internal.h"
  7.  
  8. /* physical addresses and offsets */
  9. //#define U2P_BASE        0x1FE00000000
  10. #define U2P_BASE        0x1c800000000
  11. #define PCI_CONF_OFFSET   0x001000000
  12. #define PCI_CONF_SIZE     0x001000000
  13. #define PCI_CONF_BASE  (U2P_BASE + PCI_CONF_OFFSET)
  14.  
  15. /* virtual address of PCI configuration space */
  16. static void *conf_addr = 0;  
  17.  
  18. /*
  19.  * virtual address of specified PCI configuration register:
  20.  * bus ... bus number (0 for top level PCI bus B, 1 for top level PCI bus A)
  21.  * dev ... device number (0 - 15)
  22.  * fn  ... function number (0 - 7)
  23.  * reg ... register number (register's position within PCI configuration header)
  24.  **/
  25. #define CONF_ADDR(bus, dev, fn, reg)   ((void *)(conf_addr + ((bus << 16) | (dev << 11) | (fn << 8) | (reg << 0))))
  26.  
  27.  
  28.  
  29. static void us2i_init(struct pci_access *a)
  30. {  
  31. }
  32.  
  33. static void us2i_cleanup(struct pci_access *a UNUSED)
  34. {
  35. }
  36.  
  37. static inline uint64_t pio_read_64(uint64_t *port)
  38. {
  39.     uint64_t rv;
  40.  
  41.     rv = *port;
  42.     memory_barrier();
  43.  
  44.     return rv;
  45. }
  46.  
  47. static int us2i_detect(struct pci_access *a)
  48. {  
  49.     /*
  50.      * Gain control over PCI configuration ports.
  51.      */
  52.     if (pio_enable((void *)PCI_CONF_BASE, PCI_CONF_SIZE, &conf_addr)) {
  53.         return 0;
  54.     }  
  55.  
  56.     int vendor_id = le16_to_cpu(pio_read_16(CONF_ADDR(0, 0, 0, PCI_VENDOR_ID)));   
  57.     int device_id = le16_to_cpu(pio_read_16(CONF_ADDR(0, 0, 0, PCI_DEVICE_ID)));
  58.    
  59.     printf("PCI: vendor id = %x\n", vendor_id);
  60.     printf("PCI: device id = %x\n", device_id);
  61.  
  62.     return vendor_id == 0x108E && device_id == 0x8000; // should be Psycho from Sun Microsystems
  63. }
  64.  
  65. /** Compute new starting position of the operation if byte twisting is used.
  66.  *
  67.  * See chapter 10.2 of the UPA to PCI Interface User's Manual.
  68.  * Note: byte twisting is used only for devices beyond the UPA
  69.  * to PCI bridge, not for the device of the bridge itself.
  70.  * Configuration registers of the bridge must be read in a different way.
  71.  *
  72.  * @param pos       The original starting position of the read/write operation.
  73.  * @param len       The length of the read/write operation (<= 4).
  74.  * @return      New starting position of the operation.
  75.  */
  76. static int byte_twist(int pos, int len)
  77. {
  78.     int end = (pos + len) % 4;
  79.     if (end == 0) {
  80.         end = 4;
  81.     }
  82.     int begin = 4 - end;   
  83.     pos = pos - pos % 4 + begin;
  84.     return pos;
  85. }
  86.  
  87. /*
  88. static int byte_twist(pos)
  89. {
  90.     return pos - pos % 4 + (3 - pos % 4);  
  91. }*/
  92.  
  93. static int us2i_read(struct pci_dev *d, int pos, byte * buf, int len)
  94. {
  95.     /*void * addr = CONF_ADDR(d->bus, d->dev, d->func, pos);   
  96.    
  97.     if (pos >= 256)
  98.         return 0;      
  99.  
  100.     switch (len) {
  101.     case 1:
  102.         us2i_read_aligned(d->bus, d->dev, d->func, pos, buf, len);
  103.         break;
  104.     case 2:
  105.         us2i_read_aligned(d->bus, d->dev, d->func, pos, buf, len);
  106.         ((u16 *) buf)[0] = cpu_to_le16(*((u16 *) buf));
  107.         break;
  108.     case 4:
  109.         us2i_read_aligned(d->bus, d->dev, d->func, pos, buf, len);
  110.         ((u32 *) buf)[0] = cpu_to_le32(*((u32 *) buf));    
  111.         break;
  112.     default:
  113.         return pci_generic_block_read(d, pos, buf, len);
  114.     }
  115.     return 1; */
  116.    
  117.    
  118.     if (len <= 4) {
  119.         int twist = d->dev != 0 || d->func != 0;
  120.         if (twist) {       
  121.             pos = byte_twist(pos, len);
  122.         }
  123.         int i;
  124.         for (i = 0; i < len; i++) {
  125.             void * addr = CONF_ADDR(d->bus, d->dev, d->func, pos + i);
  126.             if (byte_twist) {
  127.                 buf[i] = pio_read_8(addr);
  128.             }
  129.             else {
  130.                 buf[len-i-1] = pio_read_8(addr);
  131.             }
  132.         }
  133.     } else {
  134.         return pci_generic_block_read(d, pos, buf, len);
  135.     }
  136.     return 1;
  137.    
  138.     /*void * addr = CONF_ADDR(d->bus, d->dev, d->func, pos);   
  139.    
  140.     if (pos >= 256)
  141.         return 0;      
  142.  
  143.     switch (len) {
  144.     case 1:
  145.         buf[0] = pio_read_8(addr);
  146.         break;
  147.     case 2:
  148.         ((u16 *) buf)[0] = cpu_to_le16(pio_read_16(addr));
  149.         break;
  150.     case 4:
  151.         ((u32 *) buf)[0] = cpu_to_le32(pio_read_32(addr));     
  152.         break;
  153.     default:
  154.         return pci_generic_block_read(d, pos, buf, len);
  155.     }
  156.     return 1; */
  157.  
  158.     /*
  159.     switch (len) {
  160.     case 1:
  161.         buf[0] = pio_read_8(CONF_ADDR(d->bus, d->dev, d->func, pos));
  162.         break;
  163.     case 2:
  164.         us2i_read(d, pos + 1, buf, 1);   // unlike PCI, sparc uses big endian
  165.         us2i_read(d, pos, buf + 1, 1);
  166.         break;
  167.     case 4:
  168.         us2i_read(d, pos + 3, buf, 1);  // endians in an ugly way ... FIX ME
  169.         us2i_read(d, pos + 2, buf + 1, 1);
  170.         us2i_read(d, pos + 1, buf + 2, 1);
  171.         us2i_read(d, pos, buf + 3, 1);     
  172.         break;
  173.     default:
  174.         return pci_generic_block_read(d, pos, buf, len);
  175.     }
  176.     return 1;
  177.     */
  178. }
  179.  
  180. static int us2i_write(struct pci_dev *d, int pos, byte * buf, int len)
  181. {
  182.     void * addr = CONF_ADDR(d->bus, d->dev, d->func, pos);
  183.  
  184.     if (pos >= 256)
  185.         return 0;
  186.  
  187.     switch (len) {
  188.     case 1:
  189.         pio_write_8(CONF_ADDR(d->bus, d->dev, d->func, pos), buf[0]);
  190.         break;
  191.     case 2:
  192.         pio_write_16(addr, le16_to_cpu(((u16 *) buf)[0]));
  193.         break;
  194.     case 4:
  195.         pio_write_32(addr, le32_to_cpu(((u32 *) buf)[0]));
  196.         break;
  197.     default:
  198.         return pci_generic_block_write(d, pos, buf, len);
  199.     }
  200.     return 1;
  201. }
  202.  
  203.  
  204. struct pci_methods pm_us2i = {
  205.     "Ultra Sparc IIi",
  206.     NULL,           /* config */
  207.     us2i_detect,
  208.     us2i_init,
  209.     us2i_cleanup,
  210.     pci_generic_scan,
  211.     pci_generic_fill_info,
  212.     us2i_read,
  213.     us2i_write,
  214.     NULL,           /* init_dev */
  215.     NULL            /* cleanup_dev */
  216. };