/*
* Copyright (c) Intel Corp. 2007.
* All Rights Reserved.
*
* Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
* develop this driver.
*
* This file is part of the Vermilion Range fb driver.
* The Vermilion Range fb driver is free software;
* you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* The Vermilion Range fb driver is distributed
* in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this driver; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* Authors:
* Thomas Hellström <thomas-at-tungstengraphics-dot-com>
* Michel Dänzer <michel-at-tungstengraphics-dot-com>
* Alan Hourihane <alanh-at-tungstengraphics-dot-com>
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/fb.h>
#include <linux/pci.h>
#include <asm/cacheflush.h>
#include <asm/tlbflush.h>
#include <linux/mmzone.h>
/* #define VERMILION_DEBUG */
#include "vermilion.h"
#define MODULE_NAME "vmlfb"
#define VML_TOHW(_val, _width) ((((_val) << (_width)) + 0x7FFF - (_val)) >> 16)
static struct mutex vml_mutex;
static struct list_head global_no_mode;
static struct list_head global_has_mode;
static struct fb_ops vmlfb_ops;
static struct vml_sys *subsys = NULL;
static char *vml_default_mode = "1024x768@60";
static struct fb_videomode defaultmode = {
NULL, 60, 1024, 768, 12896, 144, 24, 29, 3, 136, 6,
0, FB_VMODE_NONINTERLACED
};
static u32 vml_mem_requested = (10 * 1024 * 1024);
static u32 vml_mem_contig = (4 * 1024 * 1024);
static u32 vml_mem_min = (4 * 1024 * 1024);
static u32 vml_clocks[] = {
6750,
13500,
27000,
29700,
37125,
54000,
59400,
74250,
120000,
148500
};
static u32 vml_num_clocks = ARRAY_SIZE(vml_clocks);
/*
* Allocate a contiguous vram area and make its linear kernel map
* uncached.
*/
static int vmlfb_alloc_vram_area(struct vram_area *va, unsigned max_order,
unsigned min_order)
{
gfp_t flags;
unsigned long i;
max_order++;
do {
/*
* Really try hard to get the needed memory.
* We need memory below the first 32MB, so we
* add the __GFP_DMA flag that guarantees that we are
* below the first 16MB.
*/
flags = __GFP_DMA | __GFP_HIGH;
va->logical =
__get_free_pages(flags, --max_order);
} while (va->logical == 0 && max_order > min_order);
if (!va->logical)
return -ENOMEM;
va->phys = virt_to_phys((void *)va->logical);
va->size = PAGE_SIZE << max_order;
va->order = max_order;
/*
* It seems like __get_free_pages only ups the usage count
* of the first page. This doesn't work with fault mapping, so
* up the usage count once more (XXX: should use split_page or
* compound page).
*/
memset((void *)va->logical, 0x00, va->size);
for (i = va->logical; i < va->logical + va->size; i += PAGE_SIZE) {
get_page(virt_to_page(i));
}
/*
* Change caching policy of the linear kernel map to avoid
* mapping type conflicts with user-space mappings.
*/
set_pages_uc(virt_to_page(va->logical), va->size >>