linux/drivers/char/agp/ati-agp.c
<<
>>
Prefs
   1/*
   2 * ATi AGPGART routines.
   3 */
   4
   5#include <linux/types.h>
   6#include <linux/module.h>
   7#include <linux/pci.h>
   8#include <linux/init.h>
   9#include <linux/string.h>
  10#include <linux/slab.h>
  11#include <linux/agp_backend.h>
  12#include <asm/agp.h>
  13#include "agp.h"
  14
  15#define ATI_GART_MMBASE_ADDR    0x14
  16#define ATI_RS100_APSIZE        0xac
  17#define ATI_RS100_IG_AGPMODE    0xb0
  18#define ATI_RS300_APSIZE        0xf8
  19#define ATI_RS300_IG_AGPMODE    0xfc
  20#define ATI_GART_FEATURE_ID             0x00
  21#define ATI_GART_BASE                   0x04
  22#define ATI_GART_CACHE_SZBASE           0x08
  23#define ATI_GART_CACHE_CNTRL            0x0c
  24#define ATI_GART_CACHE_ENTRY_CNTRL      0x10
  25
  26
  27static const struct aper_size_info_lvl2 ati_generic_sizes[7] =
  28{
  29        {2048, 524288, 0x0000000c},
  30        {1024, 262144, 0x0000000a},
  31        {512, 131072, 0x00000008},
  32        {256, 65536, 0x00000006},
  33        {128, 32768, 0x00000004},
  34        {64, 16384, 0x00000002},
  35        {32, 8192, 0x00000000}
  36};
  37
  38static struct gatt_mask ati_generic_masks[] =
  39{
  40        { .mask = 1, .type = 0}
  41};
  42
  43
  44struct ati_page_map {
  45        unsigned long *real;
  46        unsigned long __iomem *remapped;
  47};
  48
  49static struct _ati_generic_private {
  50        volatile u8 __iomem *registers;
  51        struct ati_page_map **gatt_pages;
  52        int num_tables;
  53} ati_generic_private;
  54
  55static int ati_create_page_map(struct ati_page_map *page_map)
  56{
  57        int i, err = 0;
  58
  59        page_map->real = (unsigned long *) __get_free_page(GFP_KERNEL);
  60        if (page_map->real == NULL)
  61                return -ENOMEM;
  62
  63        set_memory_uc((unsigned long)page_map->real, 1);
  64        err = map_page_into_agp(virt_to_page(page_map->real));
  65        page_map->remapped = page_map->real;
  66
  67        for (i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) {
  68                writel(agp_bridge->scratch_page, page_map->remapped+i);
  69                readl(page_map->remapped+i);    /* PCI Posting. */
  70        }
  71
  72        return 0;
  73}
  74
  75
  76static void ati_free_page_map(struct ati_page_map *page_map)
  77{
  78        unmap_page_from_agp(virt_to_page(page_map->real));
  79        set_memory_wb((unsigned long)page_map->real, 1);
  80        free_page((unsigned long) page_map->real);
  81}
  82
  83
  84static void ati_free_gatt_pages(void)
  85{
  86        int i;
  87        struct ati_page_map **tables;
  88        struct ati_page_map *entry;
  89
  90        tables = ati_generic_private.gatt_pages;
  91        for (i = 0; i < ati_generic_private.num_tables; i++) {
  92                entry = tables[i];
  93                if (entry != NULL) {
  94                        if (entry->real != NULL)
  95                                ati_free_page_map(entry);
  96                        kfree(entry);
  97                }
  98        }
  99        kfree(tables);
 100}
 101
 102
 103static int ati_create_gatt_pages(int nr_tables)
 104{
 105        struct ati_page_map **tables;
 106        struct ati_page_map *entry;
 107        int retval = 0;
 108        int i;
 109
 110        tables = kzalloc((nr_tables + 1) * sizeof(struct ati_page_map *),GFP_KERNEL);
 111        if (tables == NULL)
 112                return -ENOMEM;
 113
 114        for (i = 0; i < nr_tables; i++) {
 115                entry = kzalloc(sizeof(struct ati_page_map), GFP_KERNEL);
 116                tables[i] = entry;
 117                if (entry == NULL) {
 118                        retval = -ENOMEM;
 119                        break;
 120                }
 121                retval = ati_create_page_map(entry);
 122                if (retval != 0)
 123                        break;
 124        }
 125        ati_generic_private.num_tables = i;
 126        ati_generic_private.gatt_pages = tables;
 127
 128        if (retval != 0)
 129                ati_free_gatt_pages();
 130
 131        return retval;
 132}
 133
 134static int is_r200(void)
 135{
 136        if ((agp_bridge->dev->device == PCI_DEVICE_ID_ATI_RS100) ||
 137            (agp_bridge->dev->device == PCI_DEVICE_ID_ATI_RS200) ||
 138            (agp_bridge->dev->device == PCI_DEVICE_ID_ATI_RS200_B) ||
 139            (agp_bridge->dev->device == PCI_DEVICE_ID_ATI_RS250))
 140                return 1;
 141        return 0;
 142}
 143
 144static int ati_fetch_size(void)
 145{
 146        int i;
 147        u32 temp;
 148        struct aper_size_info_lvl2 *values;
 149
 150        if (is_r200())
 151                pci_read_config_dword(agp_bridge->dev, ATI_RS100_APSIZE, &temp);
 152        else
 153                pci_read_config_dword(agp_bridge->dev, ATI_RS300_APSIZE, &temp);
 154
 155        temp = (temp & 0x0000000e);
 156        values = A_SIZE_LVL2(agp_bridge->driver->aperture_sizes);
 157        for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {
 158                if (temp == values[i].size_value) {
 159                        agp_bridge->previous_size =
 160                            agp_bridge->current_size = (void *) (values + i);
 161
 162                        agp_bridge->aperture_size_idx = i;
 163                        return values[i].size;
 164                }
 165        }
 166
 167        return 0;
 168}
 169
 170static void ati_tlbflush(struct agp_memory * mem)
 171{
 172        writel(1, ati_generic_private.registers+ATI_GART_CACHE_CNTRL);
 173        readl(ati_generic_private.registers+ATI_GART_CACHE_CNTRL);      /* PCI Posting. */
 174}
 175
 176static void ati_cleanup(void)
 177{
 178        struct aper_size_info_lvl2 *previous_size;
 179        u32 temp;
 180
 181        previous_size = A_SIZE_LVL2(agp_bridge->previous_size);
 182
 183        /* Write back the previous size and disable gart translation */
 184        if (is_r200()) {
 185                pci_read_config_dword(agp_bridge->dev, ATI_RS100_APSIZE, &temp);
 186                temp = ((temp & ~(0x0000000f)) | previous_size->size_value);
 187                pci_write_config_dword(agp_bridge->dev, ATI_RS100_APSIZE, temp);
 188        } else {
 189                pci_read_config_dword(agp_bridge->dev, ATI_RS300_APSIZE, &temp);
 190                temp = ((temp & ~(0x0000000f)) | previous_size->size_value);
 191                pci_write_config_dword(agp_bridge->dev, ATI_RS300_APSIZE, temp);
 192        }
 193        iounmap((volatile u8 __iomem *)ati_generic_private.registers);
 194}
 195
 196
 197static int ati_configure(void)
 198{
 199        u32 temp;
 200
 201        /* Get the memory mapped registers */
 202        pci_read_config_dword(agp_bridge->dev, ATI_GART_MMBASE_ADDR, &temp);
 203        temp = (temp & 0xfffff000);
 204        ati_generic_private.registers = (volatile u8 __iomem *) ioremap(temp, 4096);
 205
 206        if (!ati_generic_private.registers)
 207                return -ENOMEM;
 208
 209        if (is_r200())
 210                pci_write_config_dword(agp_bridge->dev, ATI_RS100_IG_AGPMODE, 0x20000);
 211        else
 212                pci_write_config_dword(agp_bridge->dev, ATI_RS300_IG_AGPMODE, 0x20000);
 213
 214        /* address to map too */
 215        /*
 216        pci_read_config_dword(agp_bridge.dev, AGP_APBASE, &temp);
 217        agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
 218        printk(KERN_INFO PFX "IGP320 gart_bus_addr: %x\n", agp_bridge.gart_bus_addr);
 219        */
 220        writel(0x60000, ati_generic_private.registers+ATI_GART_FEATURE_ID);
 221        readl(ati_generic_private.registers+ATI_GART_FEATURE_ID);       /* PCI Posting.*/
 222
 223        /* SIGNALED_SYSTEM_ERROR @ NB_STATUS */
 224        pci_read_config_dword(agp_bridge->dev, 4, &temp);
 225        pci_write_config_dword(agp_bridge->dev, 4, temp | (1<<14));
 226
 227        /* Write out the address of the gatt table */
 228        writel(agp_bridge->gatt_bus_addr, ati_generic_private.registers+ATI_GART_BASE);
 229        readl(ati_generic_private.registers+ATI_GART_BASE);     /* PCI Posting. */
 230
 231        return 0;
 232}
 233
 234
 235#ifdef CONFIG_PM
 236static int agp_ati_suspend(struct pci_dev *dev, pm_message_t state)
 237{
 238        pci_save_state(dev);
 239        pci_set_power_state(dev, 3);
 240
 241        return 0;
 242}
 243
 244static int agp_ati_resume(struct pci_dev *dev)
 245{
 246        pci_set_power_state(dev, 0);
 247        pci_restore_state(dev);
 248
 249        return ati_configure();
 250}
 251#endif
 252
 253/*
 254 *Since we don't need contiguous memory we just try
 255 * to get the gatt table once
 256 */
 257
 258#define GET_PAGE_DIR_OFF(addr) (addr >> 22)
 259#define GET_PAGE_DIR_IDX(addr) (GET_PAGE_DIR_OFF(addr) - \
 260        GET_PAGE_DIR_OFF(agp_bridge->gart_bus_addr))
 261#define GET_GATT_OFF(addr) ((addr & 0x003ff000) >> 12)
 262#undef  GET_GATT
 263#define GET_GATT(addr) (ati_generic_private.gatt_pages[\
 264        GET_PAGE_DIR_IDX(addr)]->remapped)
 265
 266static int ati_insert_memory(struct agp_memory * mem,
 267                             off_t pg_start, int type)
 268{
 269        int i, j, num_entries;
 270        unsigned long __iomem *cur_gatt;
 271        unsigned long addr;
 272        int mask_type;
 273
 274        num_entries = A_SIZE_LVL2(agp_bridge->current_size)->num_entries;
 275
 276        mask_type = agp_generic_type_to_mask_type(mem->bridge, type);
 277        if (mask_type != 0 || type != mem->type)
 278                return -EINVAL;
 279
 280        if (mem->page_count == 0)
 281                return 0;
 282
 283        if ((pg_start + mem->page_count) > num_entries)
 284                return -EINVAL;
 285
 286        j = pg_start;
 287        while (j < (pg_start + mem->page_count)) {
 288                addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr;
 289                cur_gatt = GET_GATT(addr);
 290                if (!PGE_EMPTY(agp_bridge,readl(cur_gatt+GET_GATT_OFF(addr))))
 291                        return -EBUSY;
 292                j++;
 293        }
 294
 295        if (!mem->is_flushed) {
 296                /*CACHE_FLUSH(); */
 297                global_cache_flush();
 298                mem->is_flushed = true;
 299        }
 300
 301        for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
 302                addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr;
 303                cur_gatt = GET_GATT(addr);
 304                writel(agp_bridge->driver->mask_memory(agp_bridge,      
 305                                                       page_to_phys(mem->pages[i]),
 306                                                       mem->type),
 307                       cur_gatt+GET_GATT_OFF(addr));
 308        }
 309        readl(GET_GATT(agp_bridge->gart_bus_addr)); /* PCI posting */
 310        agp_bridge->driver->tlb_flush(mem);
 311        return 0;
 312}
 313
 314static int ati_remove_memory(struct agp_memory * mem, off_t pg_start,
 315                             int type)
 316{
 317        int i;
 318        unsigned long __iomem *cur_gatt;
 319        unsigned long addr;
 320        int mask_type;
 321
 322        mask_type = agp_generic_type_to_mask_type(mem->bridge, type);
 323        if (mask_type != 0 || type != mem->type)
 324                return -EINVAL;
 325
 326        if (mem->page_count == 0)
 327                return 0;
 328
 329        for (i = pg_start; i < (mem->page_count + pg_start); i++) {
 330                addr = (i * PAGE_SIZE) + agp_bridge->gart_bus_addr;
 331                cur_gatt = GET_GATT(addr);
 332                writel(agp_bridge->scratch_page, cur_gatt+GET_GATT_OFF(addr));
 333        }
 334
 335        readl(GET_GATT(agp_bridge->gart_bus_addr)); /* PCI posting */
 336        agp_bridge->driver->tlb_flush(mem);
 337        return 0;
 338}
 339
 340static int ati_create_gatt_table(struct agp_bridge_data *bridge)
 341{
 342        struct aper_size_info_lvl2 *value;
 343        struct ati_page_map page_dir;
 344        unsigned long __iomem *cur_gatt;
 345        unsigned long addr;
 346        int retval;
 347        u32 temp;
 348        int i;
 349        struct aper_size_info_lvl2 *current_size;
 350
 351        value = A_SIZE_LVL2(agp_bridge->current_size);
 352        retval = ati_create_page_map(&page_dir);
 353        if (retval != 0)
 354                return retval;
 355
 356        retval = ati_create_gatt_pages(value->num_entries / 1024);
 357        if (retval != 0) {
 358                ati_free_page_map(&page_dir);
 359                return retval;
 360        }
 361
 362        agp_bridge->gatt_table_real = (u32 *)page_dir.real;
 363        agp_bridge->gatt_table = (u32 __iomem *) page_dir.remapped;
 364        agp_bridge->gatt_bus_addr = virt_to_phys(page_dir.real);
 365
 366        /* Write out the size register */
 367        current_size = A_SIZE_LVL2(agp_bridge->current_size);
 368
 369        if (is_r200()) {
 370                pci_read_config_dword(agp_bridge->dev, ATI_RS100_APSIZE, &temp);
 371                temp = (((temp & ~(0x0000000e)) | current_size->size_value)
 372                        | 0x00000001);
 373                pci_write_config_dword(agp_bridge->dev, ATI_RS100_APSIZE, temp);
 374                pci_read_config_dword(agp_bridge->dev, ATI_RS100_APSIZE, &temp);
 375        } else {
 376                pci_read_config_dword(agp_bridge->dev, ATI_RS300_APSIZE, &temp);
 377                temp = (((temp & ~(0x0000000e)) | current_size->size_value)
 378                        | 0x00000001);
 379                pci_write_config_dword(agp_bridge->dev, ATI_RS300_APSIZE, temp);
 380                pci_read_config_dword(agp_bridge->dev, ATI_RS300_APSIZE, &temp);
 381        }
 382
 383        /*
 384         * Get the address for the gart region.
 385         * This is a bus address even on the alpha, b/c its
 386         * used to program the agp master not the cpu
 387         */
 388        pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
 389        addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
 390        agp_bridge->gart_bus_addr = addr;
 391
 392        /* Calculate the agp offset */
 393        for (i = 0; i < value->num_entries / 1024; i++, addr += 0x00400000) {
 394                writel(virt_to_phys(ati_generic_private.gatt_pages[i]->real) | 1,
 395                        page_dir.remapped+GET_PAGE_DIR_OFF(addr));
 396                readl(page_dir.remapped+GET_PAGE_DIR_OFF(addr));        /* PCI Posting. */
 397        }
 398
 399        for (i = 0; i < value->num_entries; i++) {
 400                addr = (i * PAGE_SIZE) + agp_bridge->gart_bus_addr;
 401                cur_gatt = GET_GATT(addr);
 402                writel(agp_bridge->scratch_page, cur_gatt+GET_GATT_OFF(addr));
 403        }
 404
 405        return 0;
 406}
 407
 408static int ati_free_gatt_table(struct agp_bridge_data *bridge)
 409{
 410        struct ati_page_map page_dir;
 411
 412        page_dir.real = (unsigned long *)agp_bridge->gatt_table_real;
 413        page_dir.remapped = (unsigned long __iomem *)agp_bridge->gatt_table;
 414
 415        ati_free_gatt_pages();
 416        ati_free_page_map(&page_dir);
 417        return 0;
 418}
 419
 420static const struct agp_bridge_driver ati_generic_bridge = {
 421        .owner                  = THIS_MODULE,
 422        .aperture_sizes         = ati_generic_sizes,
 423        .size_type              = LVL2_APER_SIZE,
 424        .num_aperture_sizes     = 7,
 425        .needs_scratch_page     = true,
 426        .configure              = ati_configure,
 427        .fetch_size             = ati_fetch_size,
 428        .cleanup                = ati_cleanup,
 429        .tlb_flush              = ati_tlbflush,
 430        .mask_memory            = agp_generic_mask_memory,
 431        .masks                  = ati_generic_masks,
 432        .agp_enable             = agp_generic_enable,
 433        .cache_flush            = global_cache_flush,
 434        .create_gatt_table      = ati_create_gatt_table,
 435        .free_gatt_table        = ati_free_gatt_table,
 436        .insert_memory          = ati_insert_memory,
 437        .remove_memory          = ati_remove_memory,
 438        .alloc_by_type          = agp_generic_alloc_by_type,
 439        .free_by_type           = agp_generic_free_by_type,
 440        .agp_alloc_page         = agp_generic_alloc_page,
 441        .agp_alloc_pages        = agp_generic_alloc_pages,
 442        .agp_destroy_page       = agp_generic_destroy_page,
 443        .agp_destroy_pages      = agp_generic_destroy_pages,
 444        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 445};
 446
 447
 448static struct agp_device_ids ati_agp_device_ids[] __devinitdata =
 449{
 450        {
 451                .device_id      = PCI_DEVICE_ID_ATI_RS100,
 452                .chipset_name   = "IGP320/M",
 453        },
 454        {
 455                .device_id      = PCI_DEVICE_ID_ATI_RS200,
 456                .chipset_name   = "IGP330/340/345/350/M",
 457        },
 458        {
 459                .device_id      = PCI_DEVICE_ID_ATI_RS200_B,
 460                .chipset_name   = "IGP345M",
 461        },
 462        {
 463                .device_id      = PCI_DEVICE_ID_ATI_RS250,
 464                .chipset_name   = "IGP7000/M",
 465        },
 466        {
 467                .device_id      = PCI_DEVICE_ID_ATI_RS300_100,
 468                .chipset_name   = "IGP9100/M",
 469        },
 470        {
 471                .device_id      = PCI_DEVICE_ID_ATI_RS300_133,
 472                .chipset_name   = "IGP9100/M",
 473        },
 474        {
 475                .device_id      = PCI_DEVICE_ID_ATI_RS300_166,
 476                .chipset_name   = "IGP9100/M",
 477        },
 478        {
 479                .device_id      = PCI_DEVICE_ID_ATI_RS300_200,
 480                .chipset_name   = "IGP9100/M",
 481        },
 482        {
 483                .device_id      = PCI_DEVICE_ID_ATI_RS350_133,
 484                .chipset_name   = "IGP9000/M",
 485        },
 486        {
 487                .device_id      = PCI_DEVICE_ID_ATI_RS350_200,
 488                .chipset_name   = "IGP9100/M",
 489        },
 490        { }, /* dummy final entry, always present */
 491};
 492
 493static int __devinit agp_ati_probe(struct pci_dev *pdev,
 494                                   const struct pci_device_id *ent)
 495{
 496        struct agp_device_ids *devs = ati_agp_device_ids;
 497        struct agp_bridge_data *bridge;
 498        u8 cap_ptr;
 499        int j;
 500
 501        cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
 502        if (!cap_ptr)
 503                return -ENODEV;
 504
 505        /* probe for known chipsets */
 506        for (j = 0; devs[j].chipset_name; j++) {
 507                if (pdev->device == devs[j].device_id)
 508                        goto found;
 509        }
 510
 511        dev_err(&pdev->dev, "unsupported Ati chipset [%04x/%04x])\n",
 512                pdev->vendor, pdev->device);
 513        return -ENODEV;
 514
 515found:
 516        bridge = agp_alloc_bridge();
 517        if (!bridge)
 518                return -ENOMEM;
 519
 520        bridge->dev = pdev;
 521        bridge->capndx = cap_ptr;
 522
 523        bridge->driver = &ati_generic_bridge;
 524
 525        dev_info(&pdev->dev, "Ati %s chipset\n", devs[j].chipset_name);
 526
 527        /* Fill in the mode register */
 528        pci_read_config_dword(pdev,
 529                        bridge->capndx+PCI_AGP_STATUS,
 530                        &bridge->mode);
 531
 532        pci_set_drvdata(pdev, bridge);
 533        return agp_add_bridge(bridge);
 534}
 535
 536static void __devexit agp_ati_remove(struct pci_dev *pdev)
 537{
 538        struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
 539
 540        agp_remove_bridge(bridge);
 541        agp_put_bridge(bridge);
 542}
 543
 544static struct pci_device_id agp_ati_pci_table[] = {
 545        {
 546        .class          = (PCI_CLASS_BRIDGE_HOST << 8),
 547        .class_mask     = ~0,
 548        .vendor         = PCI_VENDOR_ID_ATI,
 549        .device         = PCI_ANY_ID,
 550        .subvendor      = PCI_ANY_ID,
 551        .subdevice      = PCI_ANY_ID,
 552        },
 553        { }
 554};
 555
 556MODULE_DEVICE_TABLE(pci, agp_ati_pci_table);
 557
 558static struct pci_driver agp_ati_pci_driver = {
 559        .name           = "agpgart-ati",
 560        .id_table       = agp_ati_pci_table,
 561        .probe          = agp_ati_probe,
 562        .remove         = agp_ati_remove,
 563#ifdef CONFIG_PM
 564        .suspend        = agp_ati_suspend,
 565        .resume         = agp_ati_resume,
 566#endif
 567};
 568
 569static int __init agp_ati_init(void)
 570{
 571        if (agp_off)
 572                return -EINVAL;
 573        return pci_register_driver(&agp_ati_pci_driver);
 574}
 575
 576static void __exit agp_ati_cleanup(void)
 577{
 578        pci_unregister_driver(&agp_ati_pci_driver);
 579}
 580
 581module_init(agp_ati_init);
 582module_exit(agp_ati_cleanup);
 583
 584MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
 585MODULE_LICENSE("GPL and additional rights");
 586
 587