Subversion Repositories HelenOS

Rev

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

Rev Author Line No. Line
4269 trochtova 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
};