linux/arch/mips/pmc-sierra/yosemite/ht.c
<<
>>
Prefs
   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 */
 416