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_BAR     1
  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        phys_addr_t reg;
 200        u32 temp;
 201
 202        /* Get the memory mapped registers */
 203        reg = pci_resource_start(agp_bridge->dev, ATI_GART_MMBASE_BAR);
 204        ati_generic_private.registers = (volatile u8 __iomem *) ioremap(reg, 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 to */
 215        /*
 216        agp_bridge.gart_bus_addr = pci_bus_address(agp_bridge.dev,
 217                                                   AGP_APERTURE_BAR);
 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, PCI_COMMAND, &temp);
 225        pci_write_config_dword(agp_bridge->dev, PCI_COMMAND, 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, PCI_D3hot);
 240
 241        return 0;
 242}
 243
 244static int agp_ati_resume(struct pci_dev *dev)
 245{
 246        pci_set_power_state(dev, PCI_D0);
 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        addr = pci_bus_address(agp_bridge->dev, AGP_APERTURE_BAR);
 389        agp_bridge->gart_bus_addr = addr;
 390
 391        /* Calculate the agp offset */
 392        for (i = 0; i < value->num_entries / 1024; i++, addr += 0x00400000) {
 393                writel(virt_to_phys(ati_generic_private.gatt_pages[i]->real) | 1,
 394                        page_dir.remapped+GET_PAGE_DIR_OFF(addr));
 395                readl(page_dir.remapped+GET_PAGE_DIR_OFF(addr));        /* PCI Posting. */
 396        }
 397
 398        for (i = 0; i < value->num_entries; i++) {
 399                addr = (i * PAGE_SIZE) + agp_bridge->gart_bus_addr;
 400                cur_gatt = GET_GATT(addr);
 401                writel(agp_bridge->scratch_page, cur_gatt+GET_GATT_OFF(addr));
 402        }
 403
 404        return 0;
 405}
 406
 407static int ati_free_gatt_table(struct agp_bridge_data *bridge)
 408{
 409        struct ati_page_map page_dir;
 410
 411        page_dir.real = (unsigned long *)agp_bridge->gatt_table_real;
 412        page_dir.remapped = (unsigned long __iomem *)agp_bridge->gatt_table;
 413
 414        ati_free_gatt_pages();
 415        ati_free_page_map(&page_dir);
 416        return 0;
 417}
 418
 419static const struct agp_bridge_driver ati_generic_bridge = {
 420        .owner                  = THIS_MODULE,
 421        .aperture_sizes         = ati_generic_sizes,
 422        .size_type              = LVL2_APER_SIZE,
 423        .num_aperture_sizes     = 7,
 424        .needs_scratch_page     = true,
 425        .configure              = ati_configure,
 426        .fetch_size             = ati_fetch_size,
 427        .cleanup                = ati_cleanup,
 428        .tlb_flush              = ati_tlbflush,
 429        .mask_memory            = agp_generic_mask_memory,
 430        .masks                  = ati_generic_masks,
 431        .agp_enable             = agp_generic_enable,
 432        .cache_flush            = global_cache_flush,
 433        .create_gatt_table      = ati_create_gatt_table,
 434        .free_gatt_table        = ati_free_gatt_table,
 435        .insert_memory          = ati_insert_memory,
 436        .remove_memory          = ati_remove_memory,
 437        .alloc_by_type          = agp_generic_alloc_by_type,
 438        .free_by_type           = agp_generic_free_by_type,
 439        .agp_alloc_page         = agp_generic_alloc_page,
 440        .agp_alloc_pages        = agp_generic_alloc_pages,
 441        .agp_destroy_page       = agp_generic_destroy_page,
 442        .agp_destroy_pages      = agp_generic_destroy_pages,
 443        .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
 444};
 445
 446
 447static struct agp_device_ids ati_agp_device_ids[] =
 448{
 449        {
 450                .device_id      = PCI_DEVICE_ID_ATI_RS100,
 451                .chipset_name   = "IGP320/M",
 452        },
 453        {
 454                .device_id      = PCI_DEVICE_ID_ATI_RS200,
 455                .chipset_name   = "IGP330/340/345/350/M",
 456        },
 457        {
 458                .device_id      = PCI_DEVICE_ID_ATI_RS200_B,
 459                .chipset_name   = "IGP345M",
 460        },
 461        {
 462                .device_id      = PCI_DEVICE_ID_ATI_RS250,
 463                .chipset_name   = "IGP7000/M",
 464        },
 465        {
 466                .device_id      = PCI_DEVICE_ID_ATI_RS300_100,
 467                .chipset_name   = "IGP9100/M",
 468        },
 469        {
 470                .device_id      = PCI_DEVICE_ID_ATI_RS300_133,
 471                .chipset_name   = "IGP9100/M",
 472        },
 473        {
 474                .device_id      = PCI_DEVICE_ID_ATI_RS300_166,
 475                .chipset_name   = "IGP9100/M",
 476        },
 477        {
 478                .device_id      = PCI_DEVICE_ID_ATI_RS300_200,
 479                .chipset_name   = "IGP9100/M",
 480        },
 481        {
 482                .device_id      = PCI_DEVICE_ID_ATI_RS350_133,
 483                .chipset_name   = "IGP9000/M",
 484        },
 485        {
 486                .device_id      = PCI_DEVICE_ID_ATI_RS350_200,
 487                .chipset_name   = "IGP9100/M",
 488        },
 489        { }, /* dummy final entry, always present */
 490};
 491
 492static int agp_ati_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 493{
 494        struct agp_device_ids *devs = ati_agp_device_ids;
 495        struct agp_bridge_data *bridge;
 496        u8 cap_ptr;
 497        int j;
 498
 499        cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
 500        if (!cap_ptr)
 501                return -ENODEV;
 502
 503        /* probe for known chipsets */
 504        for (j = 0; devs[j].chipset_name; j++) {
 505                if (pdev->device == devs[j].device_id)
 506                        goto found;
 507        }
 508
 509        dev_err(&pdev->dev, "unsupported Ati chipset [%04x/%04x])\n",
 510                pdev->vendor, pdev->device);
 511        return -ENODEV;
 512
 513found:
 514        bridge = agp_alloc_bridge();
 515        if (!bridge)
 516                return -ENOMEM;
 517
 518        bridge->dev = pdev;
 519        bridge->capndx = cap_ptr;
 520
 521        bridge->driver = &ati_generic_bridge;
 522
 523        dev_info(&pdev->dev, "Ati %s chipset\n", devs[j].chipset_name);
 524
 525        /* Fill in the mode register */
 526        pci_read_config_dword(pdev,
 527                        bridge->capndx+PCI_AGP_STATUS,
 528                        &bridge->mode);
 529
 530        pci_set_drvdata(pdev, bridge);
 531        return agp_add_bridge(bridge);
 532}
 533
 534static void agp_ati_remove(struct pci_dev *pdev)
 535{
 536        struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
 537
 538        agp_remove_bridge(bridge);
 539        agp_put_bridge(bridge);
 540}
 541
 542static struct pci_device_id agp_ati_pci_table[] = {
 543        {
 544        .class          = (PCI_CLASS_BRIDGE_HOST << 8),
 545        .class_mask     = ~0,
 546        .vendor         = PCI_VENDOR_ID_ATI,
 547        .device         = PCI_ANY_ID,
 548        .subvendor      = PCI_ANY_ID,
 549        .subdevice      = PCI_ANY_ID,
 550        },
 551        { }
 552};
 553
 554MODULE_DEVICE_TABLE(pci, agp_ati_pci_table);
 555
 556static struct pci_driver agp_ati_pci_driver = {
 557        .name           = "agpgart-ati",
 558        .id_table       = agp_ati_pci_table,
 559        .probe          = agp_ati_probe,
 560        .remove         = agp_ati_remove,
 561#ifdef CONFIG_PM
 562        .suspend        = agp_ati_suspend,
 563        .resume         = agp_ati_resume,
 564#endif
 565};
 566
 567static int __init agp_ati_init(void)
 568{
 569        if (agp_off)
 570                return -EINVAL;
 571        return pci_register_driver(&agp_ati_pci_driver);
 572}
 573
 574static void __exit agp_ati_cleanup(void)
 575{
 576        pci_unregister_driver(&agp_ati_pci_driver);
 577}
 578
 579module_init(agp_ati_init);
 580module_exit(agp_ati_cleanup);
 581
 582MODULE_AUTHOR("Dave Jones");
 583MODULE_LICENSE("GPL and additional rights");
 584
 585