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 = kcalloc(nr_tables + 1, sizeof(struct ati_page_map *),
 112                         GFP_KERNEL);
 113        if (tables == NULL)
 114                return -ENOMEM;
 115
 116        for (i = 0; i < nr_tables; i++) {
 117                entry = kzalloc(sizeof(struct ati_page_map), GFP_KERNEL);
 118                tables[i] = entry;
 119                if (entry == NULL) {
 120                        retval = -ENOMEM;
 121                        break;
 122                }
 123                retval = ati_create_page_map(entry);
 124                if (retval != 0)
 125                        break;
 126        }
 127        ati_generic_private.num_tables = i;
 128        ati_generic_private.gatt_pages = tables;
 129
 130        if (retval != 0)
 131                ati_free_gatt_pages();
 132
 133        return retval;
 134}
 135
 136static int is_r200(void)
 137{
 138        if ((agp_bridge->dev->device == PCI_DEVICE_ID_ATI_RS100) ||
 139            (agp_bridge->dev->device == PCI_DEVICE_ID_ATI_RS200) ||
 140            (agp_bridge->dev->device == PCI_DEVICE_ID_ATI_RS200_B) ||
 141            (agp_bridge->dev->device == PCI_DEVICE_ID_ATI_RS250))
 142                return 1;
 143        return 0;
 144}
 145
 146static int ati_fetch_size(void)
 147{
 148        int i;
 149        u32 temp;
 150        struct aper_size_info_lvl2 *values;
 151
 152        if (is_r200())
 153                pci_read_config_dword(agp_bridge->dev, ATI_RS100_APSIZE, &temp);
 154        else
 155                pci_read_config_dword(agp_bridge->dev, ATI_RS300_APSIZE, &temp);
 156
 157        temp = (temp & 0x0000000e);
 158        values = A_SIZE_LVL2(agp_bridge->driver->aperture_sizes);
 159        for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {
 160                if (temp == values[i].size_value) {
 161                        agp_bridge->previous_size =
 162                            agp_bridge->current_size = (void *) (values + i);
 163
 164                        agp_bridge->aperture_size_idx = i;
 165                        return values[i].size;
 166                }
 167        }
 168
 169        return 0;
 170}
 171
 172static void ati_tlbflush(struct agp_memory * mem)
 173{
 174        writel(1, ati_generic_private.registers+ATI_GART_CACHE_CNTRL);
 175        readl(ati_generic_private.registers+ATI_GART_CACHE_CNTRL);      /* PCI Posting. */
 176}
 177
 178static void ati_cleanup(void)
 179{
 180        struct aper_size_info_lvl2 *previous_size;
 181        u32 temp;
 182
 183        previous_size = A_SIZE_LVL2(agp_bridge->previous_size);
 184
 185        /* Write back the previous size and disable gart translation */
 186        if (is_r200()) {
 187                pci_read_config_dword(agp_bridge->dev, ATI_RS100_APSIZE, &temp);
 188                temp = ((temp & ~(0x0000000f)) | previous_size->size_value);
 189                pci_write_config_dword(agp_bridge->dev, ATI_RS100_APSIZE, temp);
 190        } else {
 191                pci_read_config_dword(agp_bridge->dev, ATI_RS300_APSIZE, &temp);
 192                temp = ((temp & ~(0x0000000f)) | previous_size->size_value);
 193                pci_write_config_dword(agp_bridge->dev, ATI_RS300_APSIZE, temp);
 194        }
 195        iounmap((volatile u8 __iomem *)ati_generic_private.registers);
 196}
 197
 198
 199static int ati_configure(void)
 200{
 201        phys_addr_t reg;
 202        u32 temp;
 203
 204        /* Get the memory mapped registers */
 205        reg = pci_resource_start(agp_bridge->dev, ATI_GART_MMBASE_BAR);
 206        ati_generic_private.registers = (volatile u8 __iomem *) ioremap(reg, 4096);
 207
 208        if (!ati_generic_private.registers)
 209                return -ENOMEM;
 210
 211        if (is_r200())
 212                pci_write_config_dword(agp_bridge->dev, ATI_RS100_IG_AGPMODE, 0x20000);
 213        else
 214                pci_write_config_dword(agp_bridge->dev, ATI_RS300_IG_AGPMODE, 0x20000);
 215
 216        /* address to map to */
 217        /*
 218        agp_bridge.gart_bus_addr = pci_bus_address(agp_bridge.dev,
 219                                                   AGP_APERTURE_BAR);
 220        printk(KERN_INFO PFX "IGP320 gart_bus_addr: %x\n", agp_bridge.gart_bus_addr);
 221        */
 222        writel(0x60000, ati_generic_private.registers+ATI_GART_FEATURE_ID);
 223        readl(ati_generic_private.registers+ATI_GART_FEATURE_ID);       /* PCI Posting.*/
 224
 225        /* SIGNALED_SYSTEM_ERROR @ NB_STATUS */
 226        pci_read_config_dword(agp_bridge->dev, PCI_COMMAND, &temp);
 227        pci_write_config_dword(agp_bridge->dev, PCI_COMMAND, temp | (1<<14));
 228
 229        /* Write out the address of the gatt table */
 230        writel(agp_bridge->gatt_bus_addr, ati_generic_private.registers+ATI_GART_BASE);
 231        readl(ati_generic_private.registers+ATI_GART_BASE);     /* PCI Posting. */
 232
 233        return 0;
 234}
 235
 236
 237#ifdef CONFIG_PM
 238static int agp_ati_suspend(struct pci_dev *dev, pm_message_t state)
 239{
 240        pci_save_state(dev);
 241        pci_set_power_state(dev, PCI_D3hot);
 242
 243        return 0;
 244}
 245
 246static int agp_ati_resume(struct pci_dev *dev)
 247{
 248        pci_set_power_state(dev, PCI_D0);
 249        pci_restore_state(dev);
 250
 251        return ati_configure();
 252}
 253#endif
 254
 255/*
 256 *Since we don't need contiguous memory we just try
 257 * to get the gatt table once
 258 */
 259
 260#define GET_PAGE_DIR_OFF(addr) (addr >> 22)
 261#define GET_PAGE_DIR_IDX(addr) (GET_PAGE_DIR_OFF(addr) - \
 262        GET_PAGE_DIR_OFF(agp_bridge->gart_bus_addr))
 263#define GET_GATT_OFF(addr) ((addr & 0x003ff000) >> 12)
 264#undef  GET_GATT
 265#define GET_GATT(addr) (ati_generic_private.gatt_pages[\
 266        GET_PAGE_DIR_IDX(addr)]->remapped)
 267
 268static int ati_insert_memory(struct agp_memory * mem,
 269                             off_t pg_start, int type)
 270{
 271        int i, j, num_entries;
 272        unsigned long __iomem *cur_gatt;
 273        unsigned long addr;
 274        int mask_type;
 275
 276        num_entries = A_SIZE_LVL2(agp_bridge->current_size)->num_entries;
 277
 278        mask_type = agp_generic_type_to_mask_type(mem->bridge, type);
 279        if (mask_type != 0 || type != mem->type)
 280                return -EINVAL;
 281
 282        if (mem->page_count == 0)
 283                return 0;
 284
 285        if ((pg_start + mem->page_count) > num_entries)
 286                return -EINVAL;
 287
 288        j = pg_start;
 289        while (j < (pg_start + mem->page_count)) {
 290                addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr;
 291                cur_gatt = GET_GATT(addr);
 292                if (!PGE_EMPTY(agp_bridge,readl(cur_gatt+GET_GATT_OFF(addr))))
 293                        return -EBUSY;
 294                j++;
 295        }
 296
 297        if (!mem->is_flushed) {
 298                /*CACHE_FLUSH(); */
 299                global_cache_flush();
 300                mem->is_flushed = true;
 301        }
 302
 303        for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
 304                addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr;
 305                cur_gatt = GET_GATT(addr);
 306                writel(agp_bridge->driver->mask_memory(agp_bridge,      
 307                                                       page_to_phys(mem->pages[i]),
 308                                                       mem->type),
 309                       cur_gatt+GET_GATT_OFF(addr));
 310        }
 311        readl(GET_GATT(agp_bridge->gart_bus_addr)); /* PCI posting */
 312        agp_bridge->driver->tlb_flush(mem);
 313        return 0;
 314}
 315
 316static int ati_remove_memory(struct agp_memory * mem, off_t pg_start,
 317                             int type)
 318{
 319        int i;
 320        unsigned long __iomem *cur_gatt;
 321        unsigned long addr;
 322        int mask_type;
 323
 324        mask_type = agp_generic_type_to_mask_type(mem->bridge, type);
 325        if (mask_type != 0 || type != mem->type)
 326                return -EINVAL;
 327
 328        if (mem->page_count == 0)
 329                return 0;
 330
 331        for (i = pg_start; i < (mem->page_count + pg_start); i++) {
 332                addr = (i * PAGE_SIZE) + agp_bridge->gart_bus_addr;
 333                cur_gatt = GET_GATT(addr);
 334                writel(agp_bridge->scratch_page, cur_gatt+GET_GATT_OFF(addr));
 335        }
 336
 337        readl(GET_GATT(agp_bridge->gart_bus_addr)); /* PCI posting */
 338        agp_bridge->driver->tlb_flush(mem);
 339        return 0;
 340}
 341
 342static int ati_create_gatt_table(struct agp_bridge_data *bridge)
 343{
 344        struct aper_size_info_lvl2 *value;
 345        struct ati_page_map page_dir;
 346        unsigned long __iomem *cur_gatt;
 347        unsigned long addr;
 348        int retval;
 349        u32 temp;
 350        int i;
 351        struct aper_size_info_lvl2 *current_size;
 352
 353        value = A_SIZE_LVL2(agp_bridge->current_size);
 354        retval = ati_create_page_map(&page_dir);
 355        if (retval != 0)
 356                return retval;
 357
 358        retval = ati_create_gatt_pages(value->num_entries / 1024);
 359        if (retval != 0) {
 360                ati_free_page_map(&page_dir);
 361                return retval;
 362        }
 363
 364        agp_bridge->gatt_table_real = (u32 *)page_dir.real;
 365        agp_bridge->gatt_table = (u32 __iomem *) page_dir.remapped;
 366        agp_bridge->gatt_bus_addr = virt_to_phys(page_dir.real);
 367
 368        /* Write out the size register */
 369        current_size = A_SIZE_LVL2(agp_bridge->current_size);
 370
 371        if (is_r200()) {
 372                pci_read_config_dword(agp_bridge->dev, ATI_RS100_APSIZE, &temp);
 373                temp = (((temp & ~(0x0000000e)) | current_size->size_value)
 374                        | 0x00000001);
 375                pci_write_config_dword(agp_bridge->dev, ATI_RS100_APSIZE, temp);
 376                pci_read_config_dword(agp_bridge->dev, ATI_RS100_APSIZE, &temp);
 377        } else {
 378                pci_read_config_dword(agp_bridge->dev, ATI_RS300_APSIZE, &temp);
 379                temp = (((temp & ~(0x0000000e)) | current_size->size_value)
 380                        | 0x00000001);
 381                pci_write_config_dword(agp_bridge->dev, ATI_RS300_APSIZE, temp);
 382                pci_read_config_dword(agp_bridge->dev, ATI_RS300_APSIZE, &temp);
 383        }
 384
 385        /*
 386         * Get the address for the gart region.
 387         * This is a bus address even on the alpha, b/c its
 388         * used to program the agp master not the cpu
 389         */
 390        addr = pci_bus_address(agp_bridge->dev, AGP_APERTURE_BAR);
 391        agp_bridge->gart_bus_addr = addr;
 392
 393        /* Calculate the agp offset */
 394        for (i = 0; i < value->num_entries / 1024; i++, addr += 0x00400000) {
 395                writel(virt_to_phys(ati_generic_private.gatt_pages[i]->real) | 1,
 396                        page_dir.remapped+GET_PAGE_DIR_OFF(addr));
 397                readl(page_dir.remapped+GET_PAGE_DIR_OFF(addr));        /* PCI Posting. */
 398        }
 399
 400        for (i = 0; i < value->num_entries; i++) {
 401                addr = (i * PAGE_SIZE) + agp_bridge->gart_bus_addr;
 402                cur_gatt = GET_GATT(addr);
 403                writel(agp_bridge->scratch_page, cur_gatt+GET_GATT_OFF(addr));
 404        }
 405
 406        return 0;
 407}
 408
 409static int ati_free_gatt_table(struct agp_bridge_data *bridge)
 410{
 411        struct ati_page_map page_dir;
 412
 413        page_dir.real = (unsigned long *)agp_bridge->gatt_table_real;
 414        page_dir.remapped = (unsigned long __iomem *)agp_bridge->gatt_table;
 415
 416        ati_free_gatt_pages();
 417        ati_free_page_map(&page_dir);
 418        return 0;
 419}
 420
 421static const struct agp_bridge_driver ati_generic_bridge = {
 422        .owner                  = THIS_MODULE,
 423        .aperture_sizes         = ati_generic_sizes,
 424        .size_type              = LVL2_APER_SIZE,
 425        .num_aperture_sizes     = 7,
 426        .needs_scratch_page     = true,
 427        .configure              = ati_configure,
 428        .fetch_size             = ati_fetch_size,
 429        .cleanup                = ati_cleanup,
 430        .tlb_flush              = ati_tlbflush,
 431        .mask_memory            = agp_generic_mask_memory,
 432        .masks                  = ati_generic_masks,
 433        .agp_enable             = agp_generic_enable,
 434        .cache_flush            = global_cache_flush,
 435        .create_gatt_table      = ati_create_gatt_table,
 436        .free_gatt_table        = ati_free_gatt_table,
 437        .insert_memory          = ati_insert_memory,
 438        .remove_memory          = ati_remove_memory,
 439        .alloc_by_type          = agp_generic_alloc_by_type,
 440        .free_by_type           = agp_generic_free_by_type,
 441        .agp_alloc_page         = agp_generic_alloc_page,
 442        .agp_alloc_pages        = agp_generic_alloc_pages,
 443        .agp_destroy_page       = agp_generic_destroy_page,
 444        .agp_destroy_pages      = agp_generic_destroy_pages,
 445        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 446};
 447
 448
 449static struct agp_device_ids ati_agp_device_ids[] =
 450{
 451        {
 452                .device_id      = PCI_DEVICE_ID_ATI_RS100,
 453                .chipset_name   = "IGP320/M",
 454        },
 455        {
 456                .device_id      = PCI_DEVICE_ID_ATI_RS200,
 457                .chipset_name   = "IGP330/340/345/350/M",
 458        },
 459        {
 460                .device_id      = PCI_DEVICE_ID_ATI_RS200_B,
 461                .chipset_name   = "IGP345M",
 462        },
 463        {
 464                .device_id      = PCI_DEVICE_ID_ATI_RS250,
 465                .chipset_name   = "IGP7000/M",
 466        },
 467        {
 468                .device_id      = PCI_DEVICE_ID_ATI_RS300_100,
 469                .chipset_name   = "IGP9100/M",
 470        },
 471        {
 472                .device_id      = PCI_DEVICE_ID_ATI_RS300_133,
 473                .chipset_name   = "IGP9100/M",
 474        },
 475        {
 476                .device_id      = PCI_DEVICE_ID_ATI_RS300_166,
 477                .chipset_name   = "IGP9100/M",
 478        },
 479        {
 480                .device_id      = PCI_DEVICE_ID_ATI_RS300_200,
 481                .chipset_name   = "IGP9100/M",
 482        },
 483        {
 484                .device_id      = PCI_DEVICE_ID_ATI_RS350_133,
 485                .chipset_name   = "IGP9000/M",
 486        },
 487        {
 488                .device_id      = PCI_DEVICE_ID_ATI_RS350_200,
 489                .chipset_name   = "IGP9100/M",
 490        },
 491        { }, /* dummy final entry, always present */
 492};
 493
 494static int agp_ati_probe(struct pci_dev *pdev, 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 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 const 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");
 585MODULE_LICENSE("GPL and additional rights");
 586
 587