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