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