Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.4.
  1/*
  2 * Copyright 2003 PMC-Sierra
  3 * Author: Manish Lachwani (lachwani@pmc-sierra.com)
  4 *
  5 *  This program is free software; you can redistribute  it and/or modify it
  6 *  under  the terms of  the GNU General  Public License as published by the
  7 *  Free Software Foundation;  either version 2 of the  License, or (at your
  8 *  option) any later version.
  9 *
 10 *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
 11 *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
 12 *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
 13 *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
 14 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 15 *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
 16 *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 17 *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
 18 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 19 *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 20 *
 21 *  You should have received a copy of the  GNU General Public License along
 22 *  with this program; if not, write  to the Free Software Foundation, Inc.,
 23 *  675 Mass Ave, Cambridge, MA 02139, USA.
 24 */
 25
 26#include <linux/types.h>
 27#include <linux/pci.h>
 28#include <linux/kernel.h>
 29#include <asm/pci.h>
 30#include <asm/io.h>
 31
 32#include <linux/init.h>
 33#include <asm/titan_dep.h>
 34
 35#ifdef CONFIG_HYPERTRANSPORT
 36
 37
 38/*
 39 * This function check if the Hypertransport Link Initialization completed. If
 40 * it did, then proceed further with scanning bus #2
 41 */
 42static __inline__ int check_titan_htlink(void)
 43{
 44        u32 val;
 45
 46        val = *(volatile uint32_t *)(RM9000x2_HTLINK_REG);
 47        if (val & 0x00000020)
 48                /* HT Link Initialization completed */
 49                return 1;
 50        else
 51                return 0;
 52}
 53
 54static int titan_ht_config_read_dword(struct pci_dev *device,
 55                                             int offset, u32* val)
 56{
 57        int dev, bus, func;
 58        uint32_t address_reg, data_reg;
 59        uint32_t address;
 60
 61        bus = device->bus->number;
 62        dev = PCI_SLOT(device->devfn);
 63        func = PCI_FUNC(device->devfn);
 64
 65	/* XXX Need to change the Bus # */
 66        if (bus > 2)
 67                address = (bus << 16) | (dev << 11) | (func << 8) | (offset & 0xfc) |
 68                                                        0x80000000 | 0x1;
 69        else
 70                address = (dev << 11) | (func << 8) | (offset & 0xfc) | 0x80000000;
 71
 72        address_reg = RM9000x2_OCD_HTCFGA;
 73        data_reg =  RM9000x2_OCD_HTCFGD;
 74
 75        RM9K_WRITE(address_reg, address);
 76        RM9K_READ(data_reg, val);
 77
 78        return PCIBIOS_SUCCESSFUL;
 79}
 80
 81
 82static int titan_ht_config_read_word(struct pci_dev *device,
 83                                             int offset, u16* val)
 84{
 85        int dev, bus, func;
 86        uint32_t address_reg, data_reg;
 87        uint32_t address;
 88
 89        bus = device->bus->number;
 90        dev = PCI_SLOT(device->devfn);
 91        func = PCI_FUNC(device->devfn);
 92
 93	/* XXX Need to change the Bus # */
 94        if (bus > 2)
 95                address = (bus << 16) | (dev << 11) | (func << 8) | (offset & 0xfc) |
 96                                                0x80000000 | 0x1;
 97        else
 98                address = (dev << 11) | (func << 8) | (offset & 0xfc) | 0x80000000;
 99
100        address_reg = RM9000x2_OCD_HTCFGA;
101        data_reg =  RM9000x2_OCD_HTCFGD;
102
103        if ((offset & 0x3) == 0)
104                offset = 0x2;
105        else
106                offset = 0x0;
107
108        RM9K_WRITE(address_reg, address);
109        RM9K_READ_16(data_reg + offset, val);
110
111        return PCIBIOS_SUCCESSFUL;
112}
113
114
115u32 longswap(unsigned long l)
116{
117        unsigned char b1, b2, b3, b4;
118
119        b1 = l&255;
120        b2 = (l>>8)&255;
121        b3 = (l>>16)&255;
122        b4 = (l>>24)&255;
123
124        return ((b1<<24) + (b2<<16) + (b3<<8) + b4);
125}
126
127
128static int titan_ht_config_read_byte(struct pci_dev *device,
129                                             int offset, u8* val)
130{
131        int dev, bus, func;
132        uint32_t address_reg, data_reg;
133        uint32_t address;
134        int offset1;
135
136        bus = device->bus->number;
137        dev = PCI_SLOT(device->devfn);
138        func = PCI_FUNC(device->devfn);
139
140	/* XXX Need to change the Bus # */
141        if (bus > 2)
142                address = (bus << 16) | (dev << 11) | (func << 8) | (offset & 0xfc) |
143                                                        0x80000000 | 0x1;
144        else
145                address = (dev << 11) | (func << 8) | (offset & 0xfc) | 0x80000000;
146
147        address_reg = RM9000x2_OCD_HTCFGA;
148        data_reg =  RM9000x2_OCD_HTCFGD;
149
150        RM9K_WRITE(address_reg, address);
151
152        if ((offset & 0x3) == 0) {
153                offset1 = 0x3;
154        }
155        if ((offset & 0x3) == 1) {
156                offset1 = 0x2;
157        }
158        if ((offset & 0x3) == 2) {
159                offset1 = 0x1;
160        }
161        if ((offset & 0x3) == 3) {
162                offset1 = 0x0;
163        }
164        RM9K_READ_8(data_reg + offset1, val);
165
166        return PCIBIOS_SUCCESSFUL;
167}
168
169
170static int titan_ht_config_write_dword(struct pci_dev *device,
171                                             int offset, u8 val)
172{
173        int dev, bus, func;
174        uint32_t address_reg, data_reg;
175        uint32_t address;
176
177        bus = device->bus->number;
178        dev = PCI_SLOT(device->devfn);
179        func = PCI_FUNC(device->devfn);
180
181	/* XXX Need to change the Bus # */
182        if (bus > 2)
183                address = (bus << 16) | (dev << 11) | (func << 8) | (offset & 0xfc) |
184                                                        0x80000000 | 0x1;
185        else
186              address = (dev << 11) | (func << 8) | (offset & 0xfc) | 0x80000000;
187
188        address_reg = RM9000x2_OCD_HTCFGA;
189        data_reg =  RM9000x2_OCD_HTCFGD;
190
191        RM9K_WRITE(address_reg, address);
192        RM9K_WRITE(data_reg, val);
193
194        return PCIBIOS_SUCCESSFUL;
195}
196
197static int titan_ht_config_write_word(struct pci_dev *device,
198                                             int offset, u8 val)
199{
200        int dev, bus, func;
201        uint32_t address_reg, data_reg;
202        uint32_t address;
203
204        bus = device->bus->number;
205        dev = PCI_SLOT(device->devfn);
206        func = PCI_FUNC(device->devfn);
207
208	/* XXX Need to change the Bus # */
209        if (bus > 2)
210                address = (bus << 16) | (dev << 11) | (func << 8) | (offset & 0xfc) |
211                                0x80000000 | 0x1;
212        else
213                address = (dev << 11) | (func << 8) | (offset & 0xfc) | 0x80000000;
214
215        address_reg = RM9000x2_OCD_HTCFGA;
216        data_reg =  RM9000x2_OCD_HTCFGD;
217
218        if ((offset & 0x3) == 0)
219                offset = 0x2;
220        else
221                offset = 0x0;
222
223        RM9K_WRITE(address_reg, address);
224        RM9K_WRITE_16(data_reg + offset, val);
225
226        return PCIBIOS_SUCCESSFUL;
227}
228
229static int titan_ht_config_write_byte(struct pci_dev *device,
230                                             int offset, u8 val)
231{
232        int dev, bus, func;
233        uint32_t address_reg, data_reg;
234        uint32_t address;
235        int offset1;
236
237        bus = device->bus->number;
238        dev = PCI_SLOT(device->devfn);
239        func = PCI_FUNC(device->devfn);
240
241	/* XXX Need to change the Bus # */
242        if (bus > 2)
243                address = (bus << 16) | (dev << 11) | (func << 8) | (offset & 0xfc) |
244                                0x80000000 | 0x1;
245        else
246                address = (dev << 11) | (func << 8) | (offset & 0xfc) | 0x80000000;
247
248        address_reg = RM9000x2_OCD_HTCFGA;
249        data_reg =  RM9000x2_OCD_HTCFGD;
250
251        RM9K_WRITE(address_reg, address);
252
253        if ((offset & 0x3) == 0) {
254             offset1 = 0x3;
255        }
256        if ((offset & 0x3) == 1) {
257             offset1 = 0x2;
258        }
259        if ((offset & 0x3) == 2) {
260             offset1 = 0x1;
261        }
262        if ((offset & 0x3) == 3) {
263            offset1 = 0x0;
264        }
265
266        RM9K_WRITE_8(data_reg + offset1, val);
267        return PCIBIOS_SUCCESSFUL;
268}
269
270
271static void titan_pcibios_set_master(struct pci_dev *dev)
272{
273        u16 cmd;
274        int bus = dev->bus->number;
275
276	if (check_titan_htlink())
277            titan_ht_config_read_word(dev, PCI_COMMAND, &cmd);
278
279	cmd |= PCI_COMMAND_MASTER;
280
281	if (check_titan_htlink())
282            titan_ht_config_write_word(dev, PCI_COMMAND, cmd);
283}
284
285
286int pcibios_enable_resources(struct pci_dev *dev)
287{
288        u16 cmd, old_cmd;
289        u8 tmp1;
290        int idx;
291        struct resource *r;
292        int bus = dev->bus->number;
293
294	if (check_titan_htlink())
295            titan_ht_config_read_word(dev, PCI_COMMAND, &cmd);
296
297	old_cmd = cmd;
298        for (idx = 0; idx < 6; idx++) {
299                r = &dev->resource[idx];
300                if (!r->start && r->end) {
301                        printk(KERN_ERR
302                               "PCI: Device %s not available because of "
303                               "resource collisions\n", pci_name(dev));
304                        return -EINVAL;
305                }
306                if (r->flags & IORESOURCE_IO)
307                        cmd |= PCI_COMMAND_IO;
308                if (r->flags & IORESOURCE_MEM)
309                        cmd |= PCI_COMMAND_MEMORY;
310        }
311        if (cmd != old_cmd) {
312		if (check_titan_htlink())
313                   titan_ht_config_write_word(dev, PCI_COMMAND, cmd);
314	}
315
316	if (check_titan_htlink())
317		titan_ht_config_read_byte(dev, PCI_CACHE_LINE_SIZE, &tmp1);
318
319	if (tmp1 != 8) {
320                printk(KERN_WARNING "PCI setting cache line size to 8 from "
321                       "%d\n", tmp1);
322	}
323
324	if (check_titan_htlink())
325		titan_ht_config_write_byte(dev, PCI_CACHE_LINE_SIZE, 8);
326
327	if (check_titan_htlink())
328		titan_ht_config_read_byte(dev, PCI_LATENCY_TIMER, &tmp1);
329
330	if (tmp1 < 32 || tmp1 == 0xff) {
331                printk(KERN_WARNING "PCI setting latency timer to 32 from %d\n",
332                       tmp1);
333	}
334
335	if (check_titan_htlink())
336		titan_ht_config_write_byte(dev, PCI_LATENCY_TIMER, 32);
337
338	return 0;
339}
340
341
342int pcibios_enable_device(struct pci_dev *dev, int mask)
343{
344        return pcibios_enable_resources(dev);
345}
346
347resource_size_t pcibios_align_resource(void *data, const struct resource *res,
348				resource_size_t size, resource_size_t align)
349{
350        struct pci_dev *dev = data;
351	resource_size_t start = res->start;
352
353        if (res->flags & IORESOURCE_IO) {
354                /* We need to avoid collisions with `mirrored' VGA ports
355                   and other strange ISA hardware, so we always want the
356                   addresses kilobyte aligned.  */
357                if (size > 0x100) {
358                        printk(KERN_ERR "PCI: I/O Region %s/%d too large"
359                               " (%ld bytes)\n", pci_name(dev),
360                                dev->resource - res, size);
361                }
362
363                start = (start + 1024 - 1) & ~(1024 - 1);
364        }
365
366	return start;
367}
368
369struct pci_ops titan_pci_ops = {
370        titan_ht_config_read_byte,
371        titan_ht_config_read_word,
372        titan_ht_config_read_dword,
373        titan_ht_config_write_byte,
374        titan_ht_config_write_word,
375        titan_ht_config_write_dword
376};
377
378void __init pcibios_fixup_bus(struct pci_bus *c)
379{
380        titan_ht_pcibios_fixup_bus(c);
381}
382
383void __init pcibios_init(void)
384{
385
386        /* Reset PCI I/O and PCI MEM values */
387	/* XXX Need to add the proper values here */
388        ioport_resource.start = 0xe0000000;
389        ioport_resource.end   = 0xe0000000 + 0x20000000 - 1;
390        iomem_resource.start  = 0xc0000000;
391        iomem_resource.end    = 0xc0000000 + 0x20000000 - 1;
392
393	/* XXX Need to add bus values */
394        pci_scan_bus(2, &titan_pci_ops, NULL);
395        pci_scan_bus(3, &titan_pci_ops, NULL);
396}
397
398/*
399 * for parsing "pci=" kernel boot arguments.
400 */
401char *pcibios_setup(char *str)
402{
403        printk(KERN_INFO "rr: pcibios_setup\n");
404        /* Nothing to do for now.  */
405
406        return str;
407}
408
409unsigned __init int pcibios_assign_all_busses(void)
410{
411        /* We want to use the PCI bus detection done by PMON */
412        return 0;
413}
414
415#endif /* CONFIG_HYPERTRANSPORT */