gma500: Move the basic driver out of staging
Subsystems (3)
PATCH 1/12 gma500: Move the basic driver out of staging
From: Alan Cox <[email protected]>
This driver supports unaccelerated KMS display, and accelerated console handling on the Intel Poulsbo, Oaktrail, Cedarview and Medfield hardware.
For the initial merge Medfield will be left out as it needs considerable further work to reach a decent standard
Begin by adding the Makefiles and Kconfig. These are not yet plumbed into the DRM layer so will have no effect on their own
---
drivers/gpu/drm/gma500/Kconfig | 26 ++++++++++++++++++++++++++ drivers/gpu/drm/gma500/Makefile | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 0 deletions(-) create mode 100644 drivers/gpu/drm/gma500/Kconfig create mode 100644 drivers/gpu/drm/gma500/Makefile
drivers/gpu/drm/gma500/Kconfig new file +26 -0
@@ -0,0 +1,26 @@ +config DRM_GMA500 + tristate "Intel GMA5/600 KMS Framebuffer" + depends on DRM && PCI && X86 && EXPERIMENTAL + select FB_CFB_COPYAREA + select FB_CFB_FILLRECT + select FB_CFB_IMAGEBLIT + select DRM_KMS_HELPER + select DRM_TTM + help + Say yes for an experimental 2D KMS framebuffer driver for the + Intel GMA500 ('Poulsbo') and other Intel IMG based graphics + devices. + +config DRM_GMA600 + bool "Intel GMA600 support (Experimental)" + depends on DRM_GMA500 + help + Say yes to include support for GMA600 (Intel Moorestown/Oaktrail) + platforms with LVDS ports. HDMI and MIPI are not currently + supported. + +config DRM_CEDARVIEW + bool "Intel Cedarview support (Experimental)" + depends on DRM_GMA500 + help + Say yes to include support for Intel Cedarview platforms
drivers/gpu/drm/gma500/Makefile new file +39 -0
@@ -0,0 +1,39 @@ +# +# KMS driver for the GMA500 +# +ccflags-y += -Iinclude/drm + +gma500_gfx-y += gem_glue.o \ + accel_2d.o \ + backlight.o \ + framebuffer.o \ + gem.o \ + gtt.o \ + intel_bios.o \ + intel_i2c.o \ + intel_opregion.o \ + mmu.o \ + power.o \ + psb_drv.o \ + psb_intel_display.o \ + psb_intel_lvds.o \ + psb_intel_modes.o \ + psb_intel_sdvo.o \ + psb_lid.o \ + psb_irq.o \ + psb_device.o \ + mid_bios.o + +gma500_gfx-$(CONFIG_DRM_CEDARVIEW) += cdv_device.o \ + cdv_intel_crt.o \ + cdv_intel_display.o \ + cdv_intel_hdmi.o \ + cdv_intel_lvds.o + +gma500_gfx-$(CONFIG_DRM_GMA600) += oaktrail_device.o \ + oaktrail_crtc.o \ + oaktrail_lvds.o \ + oaktrail_hdmi.o \ + oaktrail_hdmi_i2c.o + +obj-$(CONFIG_DRM_GMA500) += gma500_gfx.o
PATCH 2/12 gma500: GEM and GEM glue
From: Alan Cox <[email protected]>
The driver uses GEM along with a couple of small bits of wrapping of its own. The only real oddity here is the support for using the 'stolen' memory rather than wasting several MB.
We use a simple resource manager as we don't need to manage our space intensively at all as we only do 2D work. We also have a GTT which is entirely GPU facing so in the Cedarview case are not even allocating from host address space.
---
drivers/gpu/drm/gma500/gem.c | 295 +++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/gma500/gem_glue.c | 89 +++++++++++ drivers/gpu/drm/gma500/gem_glue.h | 2 3 files changed, 386 insertions(+), 0 deletions(-) create mode 100644 drivers/gpu/drm/gma500/gem.c create mode 100644 drivers/gpu/drm/gma500/gem_glue.c create mode 100644 drivers/gpu/drm/gma500/gem_glue.h
drivers/gpu/drm/gma500/gem.c new file +295 -0
@@ -0,0 +1,295 @@ +/* +* psb GEM interface +* +* Copyright (c) 2011, Intel Corporation. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation, Inc., +* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +* +* Authors: Alan Cox +* +* TODO: +* - we need to work out if the MMU is relevant (eg for +* accelerated operations on a GEM object) +*/ + +#include <drm/drmP.h> +#include <drm/drm.h> +#include "psb_drm.h" +#include "psb_drv.h" + +int psb_gem_init_object (struct drm_gem_object *obj) +{ +return -EINVAL ; +} + +void psb_gem_free_object (struct drm_gem_object *obj) +{ + struct gtt_range *gtt = container_of(obj, struct gtt_range, gem); +drm_gem_object_release_wrap (obj); +/* This must occur last as it frees up the memory of the GEM object */ +psb_gtt_free_range (obj->dev, gtt); +} + +int psb_gem_get_aperture (struct drm_device *dev,void *data, +struct drm_file *file) +{ +return -EINVAL ; +} + +/** +* psb_gem_dumb_map_gtt - buffer mapping for dumb interface +* @file: our drm client file +* @dev: drm device +* @handle: GEM handle to the object (from dumb_create) +* +* Do the necessary setup to allow the mapping of the frame buffer +* into user memory. We don't have to do much here at the moment. +*/ +int psb_gem_dumb_map_gtt (struct drm_file *file,struct drm_device *dev, +uint32_t handle,uint64_t *offset) +{ +int ret =0 ; +struct drm_gem_object *obj; + +if (!(dev->driver->driver_features &DRIVER_GEM )) +return -ENODEV ; + +mutex_lock (&dev->struct_mutex); + +/* GEM does all our handle to object mapping */ + obj =drm_gem_object_lookup (dev, file, handle); +if (obj ==NULL ) { + ret = -ENOENT ; + goto unlock; + } +/* What validation is needed here ? */ + +/* Make it mmapable */ +if (!obj->map_list.map) { + ret =gem_create_mmap_offset (obj); +if (ret) + goto out; + } +/* GEM should really work out the hash offsets for us */ + *offset = (u64 )obj->map_list.hash.key <<PAGE_SHIFT ; +out: +drm_gem_object_unreference (obj); +unlock: +mutex_unlock (&dev->struct_mutex); +return ret; +} + +/** +* psb_gem_create - create a mappable object +* @file: the DRM file of the client +* @dev: our device +* @size: the size requested +* @handlep: returned handle (opaque number) +* +* Create a GEM object, fill in the boilerplate and attach a handle to +* it so that userspace can speak about it. This does the core work +* for the various methods that do/will create GEM objects for things +*/ +static int psb_gem_create (struct drm_file *file, +struct drm_device *dev,uint64_t size,uint32_t *handlep) +{ +struct gtt_range *r; +int ret; +u32 handle; + + size =roundup (size,PAGE_SIZE ); + +/* Allocate our object - for now a direct gtt range which is not +stolen memory backed */ + r =psb_gtt_alloc_range (dev, size,"gem" ,0 ); +if (r ==NULL ) { +dev_err (dev->dev,"no memory for %lld byte GEM object\n" , size); +return -ENOSPC ; + } +/* Initialize the extra goodies GEM needs to do all the hard work */ +if (drm_gem_object_init (dev, &r->gem, size) !=0 ) { +psb_gtt_free_range (dev, r); +/* GEM doesn't give an error code and we don't have an +EGEMSUCKS so make something up for now - FIXME */ +dev_err (dev->dev,"GEM init failed for %lld\n" , size); +return -ENOMEM ; + } +/* Give the object a handle so we can carry it more easily */ + ret =drm_gem_handle_create (file, &r->gem, &handle); +if (ret) { +dev_err (dev->dev,"GEM handle failed for %p, %lld\n" , + &r->gem, size); +drm_gem_object_release (&r->gem); +psb_gtt_free_range (dev, r); +return ret; + } +/* We have the initial and handle reference but need only one now */ +drm_gem_object_unreference (&r->gem); + *handlep = handle; +return 0 ; +} + +/** +* psb_gem_dumb_create - create a dumb buffer +* @drm_file: our client file +* @dev: our device +* @args: the requested arguments copied from userspace +* +* Allocate a buffer suitable for use for a frame buffer of the +* form described by user space. Give userspace a handle by which +* to reference it. +*/ +int psb_gem_dumb_create (struct drm_file *file,struct drm_device *dev, +struct drm_mode_create_dumb *args) +{ + args->pitch =ALIGN (args->width * ((args->bpp +7 ) /8 ),64 ); + args->size = args->pitch * args->height; +return psb_gem_create (file, dev, args->size, &args->handle); +} + +/** +* psb_gem_dumb_destroy - destroy a dumb buffer +* @file: client file +* @dev: our DRM device +* @handle: the object handle +* +* Destroy a handle that was created via psb_gem_dumb_create, at least +* we hope it was created that way. i915 seems to assume the caller +* does the checking but that might be worth review ! FIXME +*/ +int psb_gem_dumb_destroy (struct drm_file *file,struct drm_device *dev, +uint32_t handle) +{ +/* No special work needed, drop the reference and see what falls out */ +return drm_gem_handle_delete (file, handle); +} + +/** +* psb_gem_fault - pagefault handler for GEM objects +* @vma: the VMA of the GEM object +* @vmf: fault detail +* +* Invoked when a fault occurs on an mmap of a GEM managed area. GEM +* does most of the work for us including the actual map/unmap calls +* but we need to do the actual page work. +* +* This code eventually needs to handle faulting objects in and out +* of the GTT and repacking it when we run out of space. We can put +* that off for now and for our simple uses +* +* The VMA was set up by GEM. In doing so it also ensured that the +* vma->vm_private_data points to the GEM object that is backing this +* mapping. +* +* FIXME +*/ +int psb_gem_fault (struct vm_area_struct *vma,struct vm_fault *vmf) +{ +struct drm_gem_object *obj; +struct gtt_range *r; +int ret; +unsigned long pfn; +pgoff_t page_offset; +struct drm_device *dev; +struct drm_psb_private *dev_priv; + + obj = vma->vm_private_data;/* GEM object */ + dev = obj->dev; + dev_priv = dev->dev_private; + + r = container_of(obj, struct gtt_range, gem); /* Get the gtt range */ + +/* Make sure we don't parallel update on a fault, nor move or remove +something from beneath our feet */ +mutex_lock (&dev->struct_mutex); + +/* For now the mmap pins the object and it stays pinned. As things +stand that will do us no harm */ +if (r->mmapping ==0 ) { + ret =psb_gtt_pin (r); +if (ret <0 ) { +dev_err (dev->dev,"gma500: pin failed: %d\n" , ret); + goto fail; + } + r->mmapping =1 ; + } + +/* Page relative to the VMA start - we must calculate this ourselves +because vmf->pgoff is the fake GEM offset */ + page_offset = ((unsigned long ) vmf->virtual_address - vma->vm_start) + >>PAGE_SHIFT ; + +/* CPU view of the page, don't go via the GART for CPU writes */ +if (r->stolen) + pfn = (dev_priv->stolen_base + r->offset) >>PAGE_SHIFT ; +else + pfn =page_to_pfn (r->pages[page_offset]); + ret =vm_insert_pfn (vma, (unsigned long )vmf->virtual_address, pfn); + +fail: +mutex_unlock (&dev->struct_mutex); +switch (ret) { +case 0 : +case -ERESTARTSYS : +case -EINTR : +return VM_FAULT_NOPAGE ; +case -ENOMEM : +return VM_FAULT_OOM ; +default : +return VM_FAULT_SIGBUS ; + } +} + +static int psb_gem_create_stolen (struct drm_file *file,struct drm_device *dev, +int size,u32 *handle) +{ +struct gtt_range *gtt =psb_gtt_alloc_range (dev, size,"gem" ,1 ); +if (gtt ==NULL ) +return -ENOMEM ; +if (drm_gem_private_object_init (dev, >t->gem, size) !=0 ) + goto free_gtt; +if (drm_gem_handle_create (file, >t->gem, handle) ==0 ) +return 0 ; +free_gtt: +psb_gtt_free_range (dev, gtt); +return -ENOMEM ; +} + +/* +* GEM interfaces for our specific client +*/ +int psb_gem_create_ioctl (struct drm_device *dev,void *data, +struct drm_file *file) +{ +struct drm_psb_gem_create *args = data; +int ret; +if (args->flags &PSB_GEM_CREATE_STOLEN ) { + ret =psb_gem_create_stolen (file, dev, args->size, + &args->handle); +if (ret ==0 ) +return 0 ; +/* Fall throguh */ + args->flags &= ~PSB_GEM_CREATE_STOLEN ; + } +return psb_gem_create (file, dev, args->size, &args->handle); +} + +int psb_gem_mmap_ioctl (struct drm_device *dev,void *data, +struct drm_file *file) +{ +struct drm_psb_gem_mmap *args = data; +return dev->driver->dumb_map_offset (file, dev, + args->handle, &args->offset); +} +
drivers/gpu/drm/gma500/gem_glue.c new file +89 -0
89 lines not on this page · raw message
drivers/gpu/drm/gma500/gem_glue.h new file +2 -0
@@ -0,0 +1,2 @@ +extern void drm_gem_object_release_wrap (struct drm_gem_object *obj); +extern int gem_create_mmap_offset (struct drm_gem_object *obj);
Re: [PATCH 02/12] gma500: GEM and GEM glue
Quoted 6 lines · Alan Cox
From: Alan Cox <[email protected]>
The driver uses GEM along with a couple of small bits of wrapping of its own. The only real oddity here is the support for using the 'stolen' memory rather than wasting several MB.
Quoted 6 lines
We use a simple resource manager as we don't need to manage our space intensively at all as we only do 2D work. We also have a GTT which is entirely GPU facing so in the Cedarview case are not even allocating from host address space.
Signed-off-by Alan Cox <[email protected]>
One tiny comment below (has no effect on the actual code) and your drm_glue.c is already merged through some patches from Rob Clarke.
[snip]
Quoted 13 lines
drivers/gpu/drm/gma500/gem.c new file +13
-0+static int psb_gem_create (struct drm_file *file, +struct drm_device *dev,uint64_t size,uint32_t *handlep) +{ +struct gtt_range *r; +int ret; +u32 handle; + + size =roundup (size,PAGE_SIZE ); + +/* Allocate our object - for now a direct gtt range which is not +stolen memory backed */ + r =psb_gtt_alloc_range (dev, size,"gem" ,0 ); +if (r ==NULL ) {
drivers/gpu/drm/gma500/gem.c line 126
Quoted 10 lines
drivers/gpu/drm/gma500/gem.c new file +10
-0+dev_err (dev->dev,"no memory for %lld byte GEM object\n" , size); +return -ENOSPC ; + } +/* Initialize the extra goodies GEM needs to do all the hard work */ +if (drm_gem_object_init (dev, &r->gem, size) !=0 ) { +psb_gtt_free_range (dev, r); +/* GEM doesn't give an error code and we don't have an +EGEMSUCKS so make something up for now - FIXME */ +dev_err (dev->dev,"GEM init failed for %lld\n" , size); +return -ENOMEM ;
Actually my drm_gem_object_init here returns -ENOMEM in the (currently only) failure case ...
Quoted 15 lines
drivers/gpu/drm/gma500/gem.c new file +15
-0+ } +/* Give the object a handle so we can carry it more easily */ + ret =drm_gem_handle_create (file, &r->gem, &handle); +if (ret) { +dev_err (dev->dev,"GEM handle failed for %p, %lld\n" , + &r->gem, size); +drm_gem_object_release (&r->gem); +psb_gtt_free_range (dev, r); +return ret; + } +/* We have the initial and handle reference but need only one now */ +drm_gem_object_unreference (&r->gem); + *handlep = handle; +return 0 ; +}
[snip]
Quoted 28 lines
drivers/gpu/drm/gma500/gem_glue.c new file +22
-0@@ -0,0 +1,89 @@ +/************************************************************************** +* Copyright (c) 2011, Intel Corporation. +* All Rights Reserved. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation, Inc., +* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +* +**************************************************************************/ + +#include <drm/drmP.h> +#include <drm/drm.h> +
drivers/gpu/drm/gma500/gem_glue.c line 32
Quoted 10 lines
drivers/gpu/drm/gma500/gem_glue.c new file +10
-0+void drm_gem_object_release_wrap (struct drm_gem_object *obj) +{ +/* Remove the list map if one is present */ +if (obj->map_list.map) { +struct drm_gem_mm *mm = obj->dev->mm_private; +struct drm_map_list *list = &obj->map_list; +drm_ht_remove_item (&mm->offset_hash, &list->hash); +drm_mm_put_block (list->file_offset_node); +kfree (list->map); + list->map =NULL ;
drm_gem_free_mmap_offset from Rob Clarke does that for you.
drivers/gpu/drm/gma500/gem_glue.c line 44
Quoted 12 lines
drivers/gpu/drm/gma500/gem_glue.c new file +12
-0+ } +drm_gem_object_release (obj); +} + +/** +* gem_create_mmap_offset - invent an mmap offset +* @obj: our object +* +* Standard implementation of offset generation for mmap as is +* duplicated in several drivers. This belongs in GEM. +*/ +int gem_create_mmap_offset (struct drm_gem_object *obj)
Already merged.
Quoted 58 lines
drivers/gpu/drm/gma500/gem_glue.c new file +45
-0+{ +struct drm_device *dev = obj->dev; +struct drm_gem_mm *mm = dev->mm_private; +struct drm_map_list *list; +struct drm_local_map *map; +int ret; + + list = &obj->map_list; + list->map =kzalloc (sizeof (struct drm_map_list ),GFP_KERNEL ); +if (list->map ==NULL ) +return -ENOMEM ; + map = list->map; + map->type = _DRM_GEM; + map->size = obj->size; + map->handle = obj; + + list->file_offset_node =drm_mm_search_free (&mm->offset_manager, + obj->size /PAGE_SIZE ,0 ,0 ); +if (!list->file_offset_node) { +dev_err (dev->dev,"failed to allocate offset for bo %d\n" , + obj->name); + ret = -ENOSPC ; + goto free_it; + } + list->file_offset_node =drm_mm_get_block (list->file_offset_node, + obj->size /PAGE_SIZE ,0 ); +if (!list->file_offset_node) { + ret = -ENOMEM ; + goto free_it; + } + list->hash.key = list->file_offset_node->start; + ret =drm_ht_insert_item (&mm->offset_hash, &list->hash); +if (ret) { +dev_err (dev->dev,"failed to add to map hash\n" ); + goto free_mm; + } +return 0 ; + +free_mm: +drm_mm_put_block (list->file_offset_node); +free_it: +kfree (list->map); + list->map =NULL ; +return ret; +}drivers/gpu/drm/gma500/gem_glue.h new file +2
-0@@ -0,0 +1,2 @@ +extern void drm_gem_object_release_wrap (struct drm_gem_object *obj); +extern int gem_create_mmap_offset (struct drm_gem_object *obj);_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
Signature · 3 lines
Daniel Vetter Mail: [email protected] Mobile: +41 (0)79 365 57 48
PATCH 3/12 gma500: introduce the GTT and MMU handling logic
In reply to Alan CoxFrom: Alan Cox <[email protected]>
This fits alongside the GEM support to manage our resources on the card itself. It's not actually clear we need to configure the MMU at all. Further research is needed before removing it entirely. For now we suck it in (slightly abused) from the old semi-free driver.
---
drivers/gpu/drm/gma500/gtt.c | 500 ++++++++++++++++++++++++ drivers/gpu/drm/gma500/gtt.h | 61 +++ drivers/gpu/drm/gma500/mmu.c | 858 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1419 insertions(+), 0 deletions(-) create mode 100644 drivers/gpu/drm/gma500/gtt.c create mode 100644 drivers/gpu/drm/gma500/gtt.h create mode 100644 drivers/gpu/drm/gma500/mmu.c
drivers/gpu/drm/gma500/gtt.c new file +500 -0
@@ -0,0 +1,500 @@ +/* +* Copyright (c) 2007, Intel Corporation. +* All Rights Reserved. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation, Inc., +* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +* +* Authors: Thomas Hellstrom <thomas-at-tungstengraphics.com> +* Alan Cox <[email protected]> +*/ + +#include <drm/drmP.h> +#include "psb_drv.h" + + +/* +* GTT resource allocator - manage page mappings in GTT space +*/ + +/** +* psb_gtt_mask_pte - generate GTT pte entry +* @pfn: page number to encode +* @type: type of memory in the GTT +* +* Set the GTT entry for the appropriate memory type. +*/ +static inline uint32_t psb_gtt_mask_pte (uint32_t pfn,int type) +{ +uint32_t mask =PSB_PTE_VALID ; + +if (type &PSB_MMU_CACHED_MEMORY ) + mask |=PSB_PTE_CACHED ; +if (type &PSB_MMU_RO_MEMORY ) + mask |=PSB_PTE_RO ; +if (type &PSB_MMU_WO_MEMORY ) + mask |=PSB_PTE_WO ; + +return (pfn <<PAGE_SHIFT ) | mask; +} + +/** +* psb_gtt_entry - find the GTT entries for a gtt_range +* @dev: our DRM device +* @r: our GTT range +* +* Given a gtt_range object return the GTT offset of the page table +* entries for this gtt_range +*/ +u32 *psb_gtt_entry (struct drm_device *dev,struct gtt_range *r) +{ +struct drm_psb_private *dev_priv = dev->dev_private; +unsigned long offset; + + offset = r->resource.start - dev_priv->gtt_mem->start; + +return dev_priv->gtt_map + (offset >>PAGE_SHIFT ); +} + +/** +* psb_gtt_insert - put an object into the GTT +* @dev: our DRM device +* @r: our GTT range +* +* Take our preallocated GTT range and insert the GEM object into +* the GTT. +* +* FIXME: gtt lock ? +*/ +static int psb_gtt_insert (struct drm_device *dev,struct gtt_range *r) +{ +u32 *gtt_slot, pte; +struct page **pages; +int i; + +if (r->pages ==NULL ) { +WARN_ON (1 ); +return -EINVAL ; + } + +WARN_ON (r->stolen);/* refcount these maybe ? */ + + gtt_slot =psb_gtt_entry (dev, r); + pages = r->pages; + +/* Make sure changes are visible to the GPU */ +set_pages_array_uc (pages, r->npage); + +/* Write our page entries into the GTT itself */ +for (i =0 ; i < r->npage; i++) { + pte =psb_gtt_mask_pte (page_to_pfn (*pages++),0 /*type*/ ); +iowrite32 (pte, gtt_slot++); + } +/* Make sure all the entries are set before we return */ +ioread32 (gtt_slot -1 ); +return 0 ; +} + +/** +* psb_gtt_remove - remove an object from the GTT +* @dev: our DRM device +* @r: our GTT range +* +* Remove a preallocated GTT range from the GTT. Overwrite all the +* page table entries with the dummy page +*/ + +static void psb_gtt_remove (struct drm_device *dev,struct gtt_range *r) +{ +struct drm_psb_private *dev_priv = dev->dev_private; +u32 *gtt_slot, pte; +int i; + +WARN_ON (r->stolen); + + gtt_slot =psb_gtt_entry (dev, r); + pte =psb_gtt_mask_pte (page_to_pfn (dev_priv->scratch_page),0 ); + +for (i =0 ; i < r->npage; i++) +iowrite32 (pte, gtt_slot++); +ioread32 (gtt_slot -1 ); +set_pages_array_wb (r->pages, r->npage); +} + +/** +* psb_gtt_attach_pages - attach and pin GEM pages +* @gt: the gtt range +* +* Pin and build an in kernel list of the pages that back our GEM object. +* While we hold this the pages cannot be swapped out +*/ +static int psb_gtt_attach_pages (struct gtt_range *gt) +{ +struct inode *inode; +struct address_space *mapping; +int i; +struct page *p; +int pages = gt->gem.size /PAGE_SIZE ; + +WARN_ON (gt->pages); + +/* This is the shared memory object that backs the GEM resource */ + inode = gt->gem.filp->f_path.dentry->d_inode; + mapping = inode->i_mapping; + + gt->pages =kmalloc (pages *sizeof (struct page *),GFP_KERNEL ); +if (gt->pages ==NULL ) +return -ENOMEM ; + gt->npage = pages; + +for (i =0 ; i < pages; i++) { +/* FIXME: review flags later */ + p =read_cache_page_gfp (mapping, i, + __GFP_COLD |GFP_KERNEL ); +if (IS_ERR (p)) + goto err; + gt->pages[i] = p; + } +return 0 ; + +err: +while (i--) +page_cache_release (gt->pages[i]); +kfree (gt->pages); + gt->pages =NULL ; +return PTR_ERR (p); +} + +/** +* psb_gtt_detach_pages - attach and pin GEM pages +* @gt: the gtt range +* +* Undo the effect of psb_gtt_attach_pages. At this point the pages +* must have been removed from the GTT as they could now be paged out +* and move bus address. +*/ +static void psb_gtt_detach_pages (struct gtt_range *gt) +{ +int i; +for (i =0 ; i < gt->npage; i++) { +/* FIXME: do we need to force dirty */ +set_page_dirty (gt->pages[i]); +page_cache_release (gt->pages[i]); + } +kfree (gt->pages); + gt->pages =NULL ; +} + +/** +* psb_gtt_pin - pin pages into the GTT +* @gt: range to pin +* +* Pin a set of pages into the GTT. The pins are refcounted so that +* multiple pins need multiple unpins to undo. +* +* Non GEM backed objects treat this as a no-op as they are always GTT +* backed objects. +*/ +int psb_gtt_pin (struct gtt_range *gt) +{ +int ret =0 ; +struct drm_device *dev = gt->gem.dev; +struct drm_psb_private *dev_priv = dev->dev_private; + +mutex_lock (&dev_priv->gtt_mutex); + +if (gt->in_gart ==0 && gt->stolen ==0 ) { + ret =psb_gtt_attach_pages (gt); +if (ret <0 ) + goto out; + ret =psb_gtt_insert (dev, gt); +if (ret <0 ) { +psb_gtt_detach_pages (gt); + goto out; + } + } + gt->in_gart++; +out: +mutex_unlock (&dev_priv->gtt_mutex); +return ret; +} + +/** +* psb_gtt_unpin - Drop a GTT pin requirement +* @gt: range to pin +* +* Undoes the effect of psb_gtt_pin. On the last drop the GEM object +* will be removed from the GTT which will also drop the page references +* and allow the VM to clean up or page stuff. +* +* Non GEM backed objects treat this as a no-op as they are always GTT +* backed objects. +*/ +void psb_gtt_unpin (struct gtt_range *gt) +{ +struct drm_device *dev = gt->gem.dev; +struct drm_psb_private *dev_priv = dev->dev_private; + +mutex_lock (&dev_priv->gtt_mutex); + +WARN_ON (!gt->in_gart); + + gt->in_gart--; +if (gt->in_gart ==0 && gt->stolen ==0 ) { +psb_gtt_remove (dev, gt); +psb_gtt_detach_pages (gt); + } +mutex_unlock (&dev_priv->gtt_mutex); +} + +/* +* GTT resource allocator - allocate and manage GTT address space +*/ + +/** +* psb_gtt_alloc_range - allocate GTT address space +* @dev: Our DRM device +* @len: length (bytes) of address space required +* @name: resource name +* @backed: resource should be backed by stolen pages +* +* Ask the kernel core to find us a suitable range of addresses +* to use for a GTT mapping. +* +* Returns a gtt_range structure describing the object, or NULL on +* error. On successful return the resource is both allocated and marked +* as in use. +*/ +struct gtt_range *psb_gtt_alloc_range (struct drm_device *dev,int len, +const char *name,int backed) +{ +struct drm_psb_private *dev_priv = dev->dev_private; +struct gtt_range *gt; +struct resource *r = dev_priv->gtt_mem; +int ret; +unsigned long start, end; + +if (backed) { +/* The start of the GTT is the stolen pages */ + start = r->start; + end = r->start + dev_priv->gtt.stolen_size -1 ; + }else { +/* The rest we will use for GEM backed objects */ + start = r->start + dev_priv->gtt.stolen_size; + end = r->end; + } + + gt =kzalloc (sizeof (struct gtt_range ),GFP_KERNEL ); +if (gt ==NULL ) +return NULL ; + gt->resource.name = name; + gt->stolen = backed; + gt->in_gart = backed; +/* Ensure this is set for non GEM objects */ + gt->gem.dev = dev; + ret =allocate_resource (dev_priv->gtt_mem, >->resource, + len, start, end,PAGE_SIZE ,NULL ,NULL ); +if (ret ==0 ) { + gt->offset = gt->resource.start - r->start; +return gt; + } +kfree (gt); +return NULL ; +} + +/** +* psb_gtt_free_range - release GTT address space +* @dev: our DRM device +* @gt: a mapping created with psb_gtt_alloc_range +* +* Release a resource that was allocated with psb_gtt_alloc_range. If the +* object has been pinned by mmap users we clean this up here currently. +*/ +void psb_gtt_free_range (struct drm_device *dev,struct gtt_range *gt) +{ +/* Undo the mmap pin if we are destroying the object */ +if (gt->mmapping) { +psb_gtt_unpin (gt); + gt->mmapping =0 ; + } +WARN_ON (gt->in_gart && !gt->stolen); +release_resource (>->resource); +kfree (gt); +} + +void psb_gtt_alloc (struct drm_device *dev) +{ +struct drm_psb_private *dev_priv = dev->dev_private; +init_rwsem (&dev_priv->gtt.sem); +} + +void psb_gtt_takedown (struct drm_device *dev) +{ +struct drm_psb_private *dev_priv = dev->dev_private; + +if (dev_priv->gtt_map) { +iounmap (dev_priv->gtt_map); + dev_priv->gtt_map =NULL ; + } +if (dev_priv->gtt_initialized) { +pci_write_config_word (dev->pdev,PSB_GMCH_CTRL , + dev_priv->gmch_ctrl); +PSB_WVDC32 (dev_priv->pge_ctl,PSB_PGETBL_CTL ); + (void )PSB_RVDC32 (PSB_PGETBL_CTL ); + } +if (dev_priv->vram_addr) +iounmap (dev_priv->gtt_map); +} + +int psb_gtt_init (struct drm_device *dev,int resume) +{ +struct drm_psb_private *dev_priv = dev->dev_private; +unsigned gtt_pages; +unsigned long stolen_size, vram_stolen_size; +unsigned i, num_pages; +unsigned pfn_base; +uint32_t vram_pages; +uint32_t dvmt_mode =0 ; +struct psb_gtt *pg; + +int ret =0 ; +uint32_t pte; + +mutex_init (&dev_priv->gtt_mutex); + +psb_gtt_alloc (dev); + pg = &dev_priv->gtt; + +/* Enable the GTT */ +pci_read_config_word (dev->pdev,PSB_GMCH_CTRL , &dev_priv->gmch_ctrl); +pci_write_config_word (dev->pdev,PSB_GMCH_CTRL , + dev_priv->gmch_ctrl | _PSB_GMCH_ENABLED); + + dev_priv->pge_ctl =PSB_RVDC32 (PSB_PGETBL_CTL ); +PSB_WVDC32 (dev_priv->pge_ctl | _PSB_PGETBL_ENABLED,PSB_PGETBL_CTL ); + (void )PSB_RVDC32 (PSB_PGETBL_CTL ); + +/* The root resource we allocate address space from */ + dev_priv->gtt_initialized =1 ; + + pg->gtt_phys_start = dev_priv->pge_ctl &PAGE_MASK ; + +/* +* FIXME: video mmu has hw bug to access 0x0D0000000, +* then make gatt start at 0x0e000,0000 +*/ + pg->mmu_gatt_start =0xE0000000 ; + + pg->gtt_start =pci_resource_start (dev->pdev,PSB_GTT_RESOURCE ); + gtt_pages =pci_resource_len (dev->pdev,PSB_GTT_RESOURCE ) + >>PAGE_SHIFT ; +/* CDV workaround */ +if (pg->gtt_start ==0 || gtt_pages ==0 ) { +dev_err (dev->dev,"GTT PCI BAR not initialized.\n" ); + gtt_pages =64 ; + pg->gtt_start = dev_priv->pge_ctl; + } + + pg->gatt_start =pci_resource_start (dev->pdev,PSB_GATT_RESOURCE ); + pg->gatt_pages =pci_resource_len (dev->pdev,PSB_GATT_RESOURCE ) + >>PAGE_SHIFT ; + dev_priv->gtt_mem = &dev->pdev->resource[PSB_GATT_RESOURCE ]; + +if (pg->gatt_pages ==0 || pg->gatt_start ==0 ) { +static struct resource fudge;/* Preferably peppermint */ + +/* This can occur on CDV SDV systems. Fudge it in this case. +We really don't care what imaginary space is being allocated +at this point */ +dev_err (dev->dev,"GATT PCI BAR not initialized.\n" ); + pg->gatt_start =0x40000000 ; + pg->gatt_pages = (128 *1024 *1024 ) >>PAGE_SHIFT ; + fudge.start =0x40000000 ; + fudge.end =0x40000000 +128 *1024 *1024 -1 ; + fudge.name ="fudge" ; + fudge.flags =IORESOURCE_MEM ; + dev_priv->gtt_mem = &fudge; + } + +pci_read_config_dword (dev->pdev,PSB_BSM , &dev_priv->stolen_base); + vram_stolen_size = pg->gtt_phys_start - dev_priv->stolen_base + -PAGE_SIZE ; + + stolen_size = vram_stolen_size; + +printk (KERN_INFO "Stolen memory information\n" ); +printk (KERN_INFO " base in RAM: 0x%x\n" , dev_priv->stolen_base); +printk (KERN_INFO " size: %luK, calculated by (GTT RAM base) - (Stolen base), seems wrong\n" , + vram_stolen_size/1024 ); + dvmt_mode = (dev_priv->gmch_ctrl >>4 ) &0x7 ; +printk (KERN_INFO " the correct size should be: %dM(dvmt mode=%d)\n" , + (dvmt_mode ==1 ) ?1 : (2 << (dvmt_mode -1 )), dvmt_mode); + +if (resume && (gtt_pages != pg->gtt_pages) && + (stolen_size != pg->stolen_size)) { +dev_err (dev->dev,"GTT resume error.\n" ); + ret = -EINVAL ; + goto out_err; + } + + pg->gtt_pages = gtt_pages; + pg->stolen_size = stolen_size; + dev_priv->vram_stolen_size = vram_stolen_size; + +/* +* Map the GTT and the stolen memory area +*/ + dev_priv->gtt_map =ioremap_nocache (pg->gtt_phys_start, + gtt_pages <<PAGE_SHIFT ); +if (!dev_priv->gtt_map) { +dev_err (dev->dev,"Failure to map gtt.\n" ); + ret = -ENOMEM ; + goto out_err; + } + + dev_priv->vram_addr =ioremap_wc (dev_priv->stolen_base, stolen_size); +if (!dev_priv->vram_addr) { +dev_err (dev->dev,"Failure to map stolen base.\n" ); + ret = -ENOMEM ; + goto out_err; + } + +/* +* Insert vram stolen pages into the GTT +*/ + + pfn_base = dev_priv->stolen_base >>PAGE_SHIFT ; + vram_pages = num_pages = vram_stolen_size >>PAGE_SHIFT ; +printk (KERN_INFO "Set up %d stolen pages starting at 0x%08x, GTT offset %dK\n" , + num_pages, pfn_base <<PAGE_SHIFT ,0 ); +for (i =0 ; i < num_pages; ++i) { + pte =psb_gtt_mask_pte (pfn_base + i,0 ); +iowrite32 (pte, dev_priv->gtt_map + i); + } + +/* +* Init rest of GTT to the scratch page to avoid accidents or scribbles +*/ + + pfn_base =page_to_pfn (dev_priv->scratch_page); + pte =psb_gtt_mask_pte (pfn_base,0 ); +for (; i < gtt_pages; ++i) +iowrite32 (pte, dev_priv->gtt_map + i); + + (void )ioread32 (dev_priv->gtt_map + i -1 ); +return 0 ; + +out_err: +psb_gtt_takedown (dev); +return ret; +}
drivers/gpu/drm/gma500/gtt.h new file +61 -0
61 lines not on this page · raw message
drivers/gpu/drm/gma500/mmu.c new file +858 -0
858 lines not on this page · raw message
Re: [PATCH 03/12] gma500: introduce the GTT and MMU handling logic
Quoted 8 lines · Alan Cox
From: Alan Cox <[email protected]>
This fits alongside the GEM support to manage our resources on the card itself. It's not actually clear we need to configure the MMU at all. Further research is needed before removing it entirely. For now we suck it in (slightly abused) from the old semi-free driver.
Signed-off-by Alan Cox <[email protected]>
One comment below where I've gone wtf ... also tons of functions that are not static, but I expect them to get used in later patches. A few more comments in the powervr mmu code. Otherwise
[snip]
drivers/gpu/drm/gma500/gtt.c line 339
Quoted 5 lines
-- +void
psb_gtt_alloc(struct drm_device *dev)drivers/gpu/drm/gma500/gtt.c new file +4
-0+{ +struct drm_psb_private *dev_priv = dev->dev_private; +init_rwsem (&dev_priv->gtt.sem); +}
... I don't get this function. Seemingly only one callsite, no header declaration for it. And I expect something called _alloc to actually alloc something ;-) Generally tons of functions not marked as static, but I expect them to get used later on in the follow-up patches.
Quoted 120 lines
drivers/gpu/drm/gma500/gtt.c new file +120
-0+void psb_gtt_takedown (struct drm_device *dev) +{ +struct drm_psb_private *dev_priv = dev->dev_private; + +if (dev_priv->gtt_map) { +iounmap (dev_priv->gtt_map); + dev_priv->gtt_map =NULL ; + } +if (dev_priv->gtt_initialized) { +pci_write_config_word (dev->pdev,PSB_GMCH_CTRL , + dev_priv->gmch_ctrl); +PSB_WVDC32 (dev_priv->pge_ctl,PSB_PGETBL_CTL ); + (void )PSB_RVDC32 (PSB_PGETBL_CTL ); + } +if (dev_priv->vram_addr) +iounmap (dev_priv->gtt_map); +} + +int psb_gtt_init (struct drm_device *dev,int resume) +{ +struct drm_psb_private *dev_priv = dev->dev_private; +unsigned gtt_pages; +unsigned long stolen_size, vram_stolen_size; +unsigned i, num_pages; +unsigned pfn_base; +uint32_t vram_pages; +uint32_t dvmt_mode =0 ; +struct psb_gtt *pg; + +int ret =0 ; +uint32_t pte; + +mutex_init (&dev_priv->gtt_mutex); + +psb_gtt_alloc (dev); + pg = &dev_priv->gtt; + +/* Enable the GTT */ +pci_read_config_word (dev->pdev,PSB_GMCH_CTRL , &dev_priv->gmch_ctrl); +pci_write_config_word (dev->pdev,PSB_GMCH_CTRL , + dev_priv->gmch_ctrl | _PSB_GMCH_ENABLED); + + dev_priv->pge_ctl =PSB_RVDC32 (PSB_PGETBL_CTL ); +PSB_WVDC32 (dev_priv->pge_ctl | _PSB_PGETBL_ENABLED,PSB_PGETBL_CTL ); + (void )PSB_RVDC32 (PSB_PGETBL_CTL ); + +/* The root resource we allocate address space from */ + dev_priv->gtt_initialized =1 ; + + pg->gtt_phys_start = dev_priv->pge_ctl &PAGE_MASK ; + +/* +* FIXME: video mmu has hw bug to access 0x0D0000000, +* then make gatt start at 0x0e000,0000 +*/ + pg->mmu_gatt_start =0xE0000000 ; + + pg->gtt_start =pci_resource_start (dev->pdev,PSB_GTT_RESOURCE ); + gtt_pages =pci_resource_len (dev->pdev,PSB_GTT_RESOURCE ) + >>PAGE_SHIFT ; +/* CDV workaround */ +if (pg->gtt_start ==0 || gtt_pages ==0 ) { +dev_err (dev->dev,"GTT PCI BAR not initialized.\n" ); + gtt_pages =64 ; + pg->gtt_start = dev_priv->pge_ctl; + } + + pg->gatt_start =pci_resource_start (dev->pdev,PSB_GATT_RESOURCE ); + pg->gatt_pages =pci_resource_len (dev->pdev,PSB_GATT_RESOURCE ) + >>PAGE_SHIFT ; + dev_priv->gtt_mem = &dev->pdev->resource[PSB_GATT_RESOURCE ]; + +if (pg->gatt_pages ==0 || pg->gatt_start ==0 ) { +static struct resource fudge;/* Preferably peppermint */ + +/* This can occur on CDV SDV systems. Fudge it in this case. +We really don't care what imaginary space is being allocated +at this point */ +dev_err (dev->dev,"GATT PCI BAR not initialized.\n" ); + pg->gatt_start =0x40000000 ; + pg->gatt_pages = (128 *1024 *1024 ) >>PAGE_SHIFT ; + fudge.start =0x40000000 ; + fudge.end =0x40000000 +128 *1024 *1024 -1 ; + fudge.name ="fudge" ; + fudge.flags =IORESOURCE_MEM ; + dev_priv->gtt_mem = &fudge; + } + +pci_read_config_dword (dev->pdev,PSB_BSM , &dev_priv->stolen_base); + vram_stolen_size = pg->gtt_phys_start - dev_priv->stolen_base + -PAGE_SIZE ; + + stolen_size = vram_stolen_size; + +printk (KERN_INFO "Stolen memory information\n" ); +printk (KERN_INFO " base in RAM: 0x%x\n" , dev_priv->stolen_base); +printk (KERN_INFO " size: %luK, calculated by (GTT RAM base) - (Stolen base), seems wrong\n" , + vram_stolen_size/1024 ); + dvmt_mode = (dev_priv->gmch_ctrl >>4 ) &0x7 ; +printk (KERN_INFO " the correct size should be: %dM(dvmt mode=%d)\n" , + (dvmt_mode ==1 ) ?1 : (2 << (dvmt_mode -1 )), dvmt_mode); + +if (resume && (gtt_pages != pg->gtt_pages) && + (stolen_size != pg->stolen_size)) { +dev_err (dev->dev,"GTT resume error.\n" ); + ret = -EINVAL ; + goto out_err; + } + + pg->gtt_pages = gtt_pages; + pg->stolen_size = stolen_size; + dev_priv->vram_stolen_size = vram_stolen_size; + +/* +* Map the GTT and the stolen memory area +*/ + dev_priv->gtt_map =ioremap_nocache (pg->gtt_phys_start, + gtt_pages <<PAGE_SHIFT ); +if (!dev_priv->gtt_map) { +dev_err (dev->dev,"Failure to map gtt.\n" );
drivers/gpu/drm/gma500/gtt.c line 470
Quoted 10 lines
drivers/gpu/drm/gma500/gtt.c new file +10
-0+ ret = -ENOMEM ; + goto out_err; + } + + dev_priv->vram_addr =ioremap_wc (dev_priv->stolen_base, stolen_size); +if (!dev_priv->vram_addr) { +dev_err (dev->dev,"Failure to map stolen base.\n" ); + ret = -ENOMEM ; + goto out_err; + }
You might want to look into the io_mapping stuff - after all this is for 32bit atoms with just 1g of kernel addressable memory. Or is the gtt of these things so puny it's not worth it?
[snip]
Quoted 35 lines
drivers/gpu/drm/gma500/mmu.c new file +29
-0@@ -0,0 +1,858 @@ +/************************************************************************** +* Copyright (c) 2007, Intel Corporation. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation, Inc., +* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +* +**************************************************************************/ +#include <drm/drmP.h> +#include "psb_drv.h" +#include "psb_reg.h" + +/* +* Code for the SGX MMU: +*/ + +/* +* clflush on one processor only: +* clflush should apparently flush the cache line on all processors in an +* SMP system.
drivers/gpu/drm/gma500/mmu.c line 39
Quoted 10 lines
drivers/gpu/drm/gma500/mmu.c new file +10
-0+*/ + +/* +* kmap atomic: +* The usage of the slots must be completely encapsulated within a spinlock, and +* no other functions that may be using the locks for other purposed may be +* called from within the locked region. +* Since the slots are per processor, this will guarantee that we are the only +* user. +*/
Afaik this comment is bogus. And the previous one sounds like it's no clear whether this holds (it does, at least for the i915.ko driver). Maybe kill them both?
Quoted 58 lines
drivers/gpu/drm/gma500/mmu.c new file +58
-0+/* +* TODO: Inserting ptes from an interrupt handler: +* This may be desirable for some SGX functionality where the GPU can fault in +* needed pages. For that, we need to make an atomic insert_pages function, that +* may fail. +* If it fails, the caller need to insert the page using a workqueue function, +* but on average it should be fast. +*/ + +struct psb_mmu_driver { +/* protects driver- and pd structures. Always take in read mode +* before taking the page table spinlock. +*/ +struct rw_semaphore sem; + +/* protects page tables, directory tables and pt tables. +* and pt structures. +*/ +spinlock_t lock; + +atomic_t needs_tlbflush; + +uint8_t __iomem *register_map; +struct psb_mmu_pd *default_pd; +/*uint32_t bif_ctrl;*/ +int has_clflush; +int clflush_add; +unsigned long clflush_mask; + +struct drm_psb_private *dev_priv; +}; + +struct psb_mmu_pd ; + +struct psb_mmu_pt { +struct psb_mmu_pd *pd; +uint32_t index; +uint32_t count; +struct page *p; +uint32_t *v; +}; + +struct psb_mmu_pd { +struct psb_mmu_driver *driver; +int hw_context; +struct psb_mmu_pt **tables; +struct page *p; +struct page *dummy_pt; +struct page *dummy_page; +uint32_t pd_mask; +uint32_t invalid_pde; +uint32_t invalid_pte; +}; + +static inline uint32_t psb_mmu_pt_index (uint32_t offset) +{ +return (offset >>PSB_PTE_SHIFT ) &0x3FF ; +}
drivers/gpu/drm/gma500/mmu.c line 108
Quoted 10 lines
drivers/gpu/drm/gma500/mmu.c new file +10
-0+ +static inline uint32_t psb_mmu_pd_index (uint32_t offset) +{ +return offset >>PSB_PDE_SHIFT ; +} + +static inline void psb_clflush (void *addr) +{ + __asm__ __volatile__("clflush (%0)\n" : :"r" (addr) :"memory" ); +}
clflush from system.h
Quoted 29 lines
drivers/gpu/drm/gma500/mmu.c new file +29
-0+static inline void psb_mmu_clflush (struct psb_mmu_driver *driver, +void *addr) +{ +if (!driver->has_clflush) +return ; + +mb (); +psb_clflush (addr); +mb (); +} + +static void psb_page_clflush (struct psb_mmu_driver *driver,struct page * page) +{ +uint32_t clflush_add = driver->clflush_add >>PAGE_SHIFT ; +uint32_t clflush_count =PAGE_SIZE / clflush_add; +int i; +uint8_t *clf; + + clf =kmap_atomic (page,KM_USER0 ); +mb (); +for (i =0 ; i < clflush_count; ++i) { +psb_clflush (clf); + clf += clflush_add; + } +mb (); +kunmap_atomic (clf,KM_USER0 ); +} + +static void psb_pages_clflush(struct psb_mmu_driver *driver,
drivers/gpu/drm/gma500/mmu.c line 148
Quoted 10 lines
drivers/gpu/drm/gma500/mmu.c new file +10
-0+ struct page *page[], unsigned long num_pages) +{ + int i; + +if (!driver->has_clflush) +return ; + +for (i =0 ; i < num_pages; i++) +psb_page_clflush (driver, *page++); +}
drm_clflush_pages does that for you.
Quoted 184 lines
drivers/gpu/drm/gma500/mmu.c new file +184
-0+ +static void psb_mmu_flush_pd_locked (struct psb_mmu_driver *driver, +int force) +{ +atomic_set (&driver->needs_tlbflush,0 ); +} + +static void psb_mmu_flush_pd (struct psb_mmu_driver *driver,int force) +{ +down_write (&driver->sem); +psb_mmu_flush_pd_locked (driver, force); +up_write (&driver->sem); +} + +void psb_mmu_flush (struct psb_mmu_driver *driver,int rc_prot) +{ +if (rc_prot) +down_write (&driver->sem); +if (rc_prot) +up_write (&driver->sem); +} + +void psb_mmu_set_pd_context (struct psb_mmu_pd *pd,int hw_context) +{ +/*ttm_tt_cache_flush(&pd->p, 1);*/ +psb_pages_clflush (pd->driver, &pd->p,1 ); +down_write (&pd->driver->sem); +wmb (); +psb_mmu_flush_pd_locked (pd->driver,1 ); + pd->hw_context = hw_context; +up_write (&pd->driver->sem); + +} + +static inline unsigned long psb_pd_addr_end (unsigned long addr, +unsigned long end) +{ + + addr = (addr +PSB_PDE_MASK +1 ) & ~PSB_PDE_MASK ; +return (addr < end) ? addr : end; +} + +static inline uint32_t psb_mmu_mask_pte (uint32_t pfn,int type) +{ +uint32_t mask =PSB_PTE_VALID ; + +if (type &PSB_MMU_CACHED_MEMORY ) + mask |=PSB_PTE_CACHED ; +if (type &PSB_MMU_RO_MEMORY ) + mask |=PSB_PTE_RO ; +if (type &PSB_MMU_WO_MEMORY ) + mask |=PSB_PTE_WO ; + +return (pfn <<PAGE_SHIFT ) | mask; +} + +struct psb_mmu_pd *psb_mmu_alloc_pd (struct psb_mmu_driver *driver, +int trap_pagefaults,int invalid_type) +{ +struct psb_mmu_pd *pd =kmalloc (sizeof (*pd),GFP_KERNEL ); +uint32_t *v; +int i; + +if (!pd) +return NULL ; + + pd->p =alloc_page (GFP_DMA32 ); +if (!pd->p) + goto out_err1; + pd->dummy_pt =alloc_page (GFP_DMA32 ); +if (!pd->dummy_pt) + goto out_err2; + pd->dummy_page =alloc_page (GFP_DMA32 ); +if (!pd->dummy_page) + goto out_err3; + +if (!trap_pagefaults) { + pd->invalid_pde = +psb_mmu_mask_pte (page_to_pfn (pd->dummy_pt), + invalid_type); + pd->invalid_pte = +psb_mmu_mask_pte (page_to_pfn (pd->dummy_page), + invalid_type); + }else { + pd->invalid_pde =0 ; + pd->invalid_pte =0 ; + } + + v =kmap (pd->dummy_pt); +for (i =0 ; i < (PAGE_SIZE /sizeof (uint32_t )); ++i) + v[i] = pd->invalid_pte; + +kunmap (pd->dummy_pt); + + v =kmap (pd->p); +for (i =0 ; i < (PAGE_SIZE /sizeof (uint32_t )); ++i) + v[i] = pd->invalid_pde; + +kunmap (pd->p); + +clear_page (kmap (pd->dummy_page)); +kunmap (pd->dummy_page); + + pd->tables =vmalloc_user (sizeof (struct psb_mmu_pt *) *1024 ); +if (!pd->tables) + goto out_err4; + + pd->hw_context =-1 ; + pd->pd_mask =PSB_PTE_VALID ; + pd->driver = driver; + +return pd; + +out_err4: +__free_page (pd->dummy_page); +out_err3: +__free_page (pd->dummy_pt); +out_err2: +__free_page (pd->p); +out_err1: +kfree (pd); +return NULL ; +} + +void psb_mmu_free_pt (struct psb_mmu_pt *pt) +{ +__free_page (pt->p); +kfree (pt); +} + +void psb_mmu_free_pagedir (struct psb_mmu_pd *pd) +{ +struct psb_mmu_driver *driver = pd->driver; +struct psb_mmu_pt *pt; +int i; + +down_write (&driver->sem); +if (pd->hw_context !=-1 ) +psb_mmu_flush_pd_locked (driver,1 ); + +/* Should take the spinlock here, but we don't need to do that +since we have the semaphore in write mode. */ + +for (i =0 ; i <1024 ; ++i) { + pt = pd->tables[i]; +if (pt) +psb_mmu_free_pt (pt); + } + +vfree (pd->tables); +__free_page (pd->dummy_page); +__free_page (pd->dummy_pt); +__free_page (pd->p); +kfree (pd); +up_write (&driver->sem); +} + +static struct psb_mmu_pt *psb_mmu_alloc_pt (struct psb_mmu_pd *pd) +{ +struct psb_mmu_pt *pt =kmalloc (sizeof (*pt),GFP_KERNEL ); +void *v; +uint32_t clflush_add = pd->driver->clflush_add >>PAGE_SHIFT ; +uint32_t clflush_count =PAGE_SIZE / clflush_add; +spinlock_t *lock = &pd->driver->lock; +uint8_t *clf; +uint32_t *ptes; +int i; + +if (!pt) +return NULL ; + + pt->p =alloc_page (GFP_DMA32 ); +if (!pt->p) { +kfree (pt); +return NULL ; + } + +spin_lock (lock); + + v =kmap_atomic (pt->p,KM_USER0 ); + clf = (uint8_t *) v; + ptes = (uint32_t *) v; +for (i =0 ; i < (PAGE_SIZE /sizeof (uint32_t )); ++i) + *ptes++ = pd->invalid_pte;
drivers/gpu/drm/gma500/mmu.c line 342
Quoted 10 lines
drivers/gpu/drm/gma500/mmu.c new file +10
-0+ + +if (pd->driver->has_clflush && pd->hw_context !=-1 ) { +mb (); +for (i =0 ; i < clflush_count; ++i) { +psb_clflush (clf); + clf += clflush_add; + } +mb (); + }
I my next patch series for i915 drm_cache.c will grow a drm_clflush_virt_range, which would perfectly fit here. I'll try not to forget gma500 ...
Quoted 520 lines
drivers/gpu/drm/gma500/mmu.c new file +515
-0+kunmap_atomic (v,KM_USER0 ); +spin_unlock (lock); + + pt->count =0 ; + pt->pd = pd; + pt->index =0 ; + +return pt; +} + +struct psb_mmu_pt *psb_mmu_pt_alloc_map_lock (struct psb_mmu_pd *pd, +unsigned long addr) +{ +uint32_t index =psb_mmu_pd_index (addr); +struct psb_mmu_pt *pt; +uint32_t *v; +spinlock_t *lock = &pd->driver->lock; + +spin_lock (lock); + pt = pd->tables[index]; +while (!pt) { +spin_unlock (lock); + pt =psb_mmu_alloc_pt (pd); +if (!pt) +return NULL ; +spin_lock (lock); + +if (pd->tables[index]) { +spin_unlock (lock); +psb_mmu_free_pt (pt); +spin_lock (lock); + pt = pd->tables[index]; +continue ; + } + + v =kmap_atomic (pd->p,KM_USER0 ); + pd->tables[index] = pt; + v[index] = (page_to_pfn (pt->p) <<12 ) | pd->pd_mask; + pt->index = index; +kunmap_atomic ((void *) v,KM_USER0 ); + +if (pd->hw_context !=-1 ) { +psb_mmu_clflush (pd->driver, (void *) &v[index]); +atomic_set (&pd->driver->needs_tlbflush,1 ); + } + } + pt->v =kmap_atomic (pt->p,KM_USER0 ); +return pt; +} + +static struct psb_mmu_pt *psb_mmu_pt_map_lock (struct psb_mmu_pd *pd, +unsigned long addr) +{ +uint32_t index =psb_mmu_pd_index (addr); +struct psb_mmu_pt *pt; +spinlock_t *lock = &pd->driver->lock; + +spin_lock (lock); + pt = pd->tables[index]; +if (!pt) { +spin_unlock (lock); +return NULL ; + } + pt->v =kmap_atomic (pt->p,KM_USER0 ); +return pt; +} + +static void psb_mmu_pt_unmap_unlock (struct psb_mmu_pt *pt) +{ +struct psb_mmu_pd *pd = pt->pd; +uint32_t *v; + +kunmap_atomic (pt->v,KM_USER0 ); +if (pt->count ==0 ) { + v =kmap_atomic (pd->p,KM_USER0 ); + v[pt->index] = pd->invalid_pde; + pd->tables[pt->index] =NULL ; + +if (pd->hw_context !=-1 ) { +psb_mmu_clflush (pd->driver, + (void *) &v[pt->index]); +atomic_set (&pd->driver->needs_tlbflush,1 ); + } +kunmap_atomic (pt->v,KM_USER0 ); +spin_unlock (&pd->driver->lock); +psb_mmu_free_pt (pt); +return ; + } +spin_unlock (&pd->driver->lock); +} + +static inline void psb_mmu_set_pte (struct psb_mmu_pt *pt, +unsigned long addr,uint32_t pte) +{ + pt->v[psb_mmu_pt_index (addr)] = pte; +} + +static inline void psb_mmu_invalidate_pte (struct psb_mmu_pt *pt, +unsigned long addr) +{ + pt->v[psb_mmu_pt_index (addr)] = pt->pd->invalid_pte; +} + + +void psb_mmu_mirror_gtt (struct psb_mmu_pd *pd, +uint32_t mmu_offset,uint32_t gtt_start, +uint32_t gtt_pages) +{ +uint32_t *v; +uint32_t start =psb_mmu_pd_index (mmu_offset); +struct psb_mmu_driver *driver = pd->driver; +int num_pages = gtt_pages; + +down_read (&driver->sem); +spin_lock (&driver->lock); + + v =kmap_atomic (pd->p,KM_USER0 ); + v += start; + +while (gtt_pages--) { + *v++ = gtt_start | pd->pd_mask; + gtt_start +=PAGE_SIZE ; + } + +/*ttm_tt_cache_flush(&pd->p, num_pages);*/ +psb_pages_clflush (pd->driver, &pd->p, num_pages); +kunmap_atomic (v,KM_USER0 ); +spin_unlock (&driver->lock); + +if (pd->hw_context !=-1 ) +atomic_set (&pd->driver->needs_tlbflush,1 ); + +up_read (&pd->driver->sem); +psb_mmu_flush_pd (pd->driver,0 ); +} + +struct psb_mmu_pd *psb_mmu_get_default_pd (struct psb_mmu_driver *driver) +{ +struct psb_mmu_pd *pd; + +/* down_read(&driver->sem); */ + pd = driver->default_pd; +/* up_read(&driver->sem); */ + +return pd; +} + +/* Returns the physical address of the PD shared by sgx/msvdx */ +uint32_t psb_get_default_pd_addr (struct psb_mmu_driver *driver) +{ +struct psb_mmu_pd *pd; + + pd =psb_mmu_get_default_pd (driver); +return page_to_pfn (pd->p) <<PAGE_SHIFT ; +} + +void psb_mmu_driver_takedown (struct psb_mmu_driver *driver) +{ +psb_mmu_free_pagedir (driver->default_pd); +kfree (driver); +} + +struct psb_mmu_driver *psb_mmu_driver_init (uint8_t __iomem * registers, +int trap_pagefaults, +int invalid_type, +struct drm_psb_private *dev_priv) +{ +struct psb_mmu_driver *driver; + + driver =kmalloc (sizeof (*driver),GFP_KERNEL ); + +if (!driver) +return NULL ; + driver->dev_priv = dev_priv; + + driver->default_pd =psb_mmu_alloc_pd (driver, trap_pagefaults, + invalid_type); +if (!driver->default_pd) + goto out_err1; + +spin_lock_init (&driver->lock); +init_rwsem (&driver->sem); +down_write (&driver->sem); + driver->register_map = registers; +atomic_set (&driver->needs_tlbflush,1 ); + + driver->has_clflush =0 ; + +if (boot_cpu_has (X86_FEATURE_CLFLSH )) { +uint32_t tfms, misc, cap0, cap4, clflush_size; + +/* +* clflush size is determined at kernel setup for x86_64 +* but not for i386. We have to do it here. +*/ + +cpuid (0x00000001 , &tfms, &misc, &cap0, &cap4); + clflush_size = ((misc >>8 ) &0xff ) *8 ; + driver->has_clflush =1 ; + driver->clflush_add = +PAGE_SIZE * clflush_size /sizeof (uint32_t ); + driver->clflush_mask = driver->clflush_add -1 ; + driver->clflush_mask = ~driver->clflush_mask; + } + +up_write (&driver->sem); +return driver; + +out_err1: +kfree (driver); +return NULL ; +} + +static void psb_mmu_flush_ptes (struct psb_mmu_pd *pd, +unsigned long address,uint32_t num_pages, +uint32_t desired_tile_stride, +uint32_t hw_tile_stride) +{ +struct psb_mmu_pt *pt; +uint32_t rows =1 ; +uint32_t i; +unsigned long addr; +unsigned long end; +unsigned long next; +unsigned long add; +unsigned long row_add; +unsigned long clflush_add = pd->driver->clflush_add; +unsigned long clflush_mask = pd->driver->clflush_mask; + +if (!pd->driver->has_clflush) { +/*ttm_tt_cache_flush(&pd->p, num_pages);*/ +psb_pages_clflush (pd->driver, &pd->p, num_pages); +return ; + } + +if (hw_tile_stride) + rows = num_pages / desired_tile_stride; +else + desired_tile_stride = num_pages; + + add = desired_tile_stride <<PAGE_SHIFT ; + row_add = hw_tile_stride <<PAGE_SHIFT ; +mb (); +for (i =0 ; i < rows; ++i) { + + addr = address; + end = addr + add; + +do { + next =psb_pd_addr_end (addr, end); + pt =psb_mmu_pt_map_lock (pd, addr); +if (!pt) +continue ; +do { +psb_clflush (&pt->v + [psb_mmu_pt_index (addr)]); + }while (addr += + clflush_add, + (addr & clflush_mask) < next); + +psb_mmu_pt_unmap_unlock (pt); + }while (addr = next, next != end); + address += row_add; + } +mb (); +} + +void psb_mmu_remove_pfn_sequence (struct psb_mmu_pd *pd, +unsigned long address,uint32_t num_pages) +{ +struct psb_mmu_pt *pt; +unsigned long addr; +unsigned long end; +unsigned long next; +unsigned long f_address = address; + +down_read (&pd->driver->sem); + + addr = address; + end = addr + (num_pages <<PAGE_SHIFT ); + +do { + next =psb_pd_addr_end (addr, end); + pt =psb_mmu_pt_alloc_map_lock (pd, addr); +if (!pt) + goto out; +do { +psb_mmu_invalidate_pte (pt, addr); + --pt->count; + }while (addr +=PAGE_SIZE , addr < next); +psb_mmu_pt_unmap_unlock (pt); + + }while (addr = next, next != end); + +out: +if (pd->hw_context !=-1 ) +psb_mmu_flush_ptes (pd, f_address, num_pages,1 ,1 ); + +up_read (&pd->driver->sem); + +if (pd->hw_context !=-1 ) +psb_mmu_flush (pd->driver,0 ); + +return ; +} + +void psb_mmu_remove_pages (struct psb_mmu_pd *pd,unsigned long address, +uint32_t num_pages,uint32_t desired_tile_stride, +uint32_t hw_tile_stride) +{ +struct psb_mmu_pt *pt; +uint32_t rows =1 ; +uint32_t i; +unsigned long addr; +unsigned long end; +unsigned long next; +unsigned long add; +unsigned long row_add; +unsigned long f_address = address; + +if (hw_tile_stride) + rows = num_pages / desired_tile_stride; +else + desired_tile_stride = num_pages; + + add = desired_tile_stride <<PAGE_SHIFT ; + row_add = hw_tile_stride <<PAGE_SHIFT ; + +/* down_read(&pd->driver->sem); */ + +/* Make sure we only need to flush this processor's cache */ + +for (i =0 ; i < rows; ++i) { + + addr = address; + end = addr + add; + +do { + next =psb_pd_addr_end (addr, end); + pt =psb_mmu_pt_map_lock (pd, addr); +if (!pt) +continue ; +do { +psb_mmu_invalidate_pte (pt, addr); + --pt->count; + + }while (addr +=PAGE_SIZE , addr < next); +psb_mmu_pt_unmap_unlock (pt); + + }while (addr = next, next != end); + address += row_add; + } +if (pd->hw_context !=-1 ) +psb_mmu_flush_ptes (pd, f_address, num_pages, + desired_tile_stride, hw_tile_stride); + +/* up_read(&pd->driver->sem); */ + +if (pd->hw_context !=-1 ) +psb_mmu_flush (pd->driver,0 ); +} + +int psb_mmu_insert_pfn_sequence (struct psb_mmu_pd *pd,uint32_t start_pfn, +unsigned long address,uint32_t num_pages, +int type) +{ +struct psb_mmu_pt *pt; +uint32_t pte; +unsigned long addr; +unsigned long end; +unsigned long next; +unsigned long f_address = address; +int ret =0 ; + +down_read (&pd->driver->sem); + + addr = address; + end = addr + (num_pages <<PAGE_SHIFT ); + +do { + next =psb_pd_addr_end (addr, end); + pt =psb_mmu_pt_alloc_map_lock (pd, addr); +if (!pt) { + ret = -ENOMEM ; + goto out; + } +do { + pte =psb_mmu_mask_pte (start_pfn++, type); +psb_mmu_set_pte (pt, addr, pte); + pt->count++; + }while (addr +=PAGE_SIZE , addr < next); +psb_mmu_pt_unmap_unlock (pt); + + }while (addr = next, next != end); + +out: +if (pd->hw_context !=-1 ) +psb_mmu_flush_ptes (pd, f_address, num_pages,1 ,1 ); + +up_read (&pd->driver->sem); + +if (pd->hw_context !=-1 ) +psb_mmu_flush (pd->driver,1 ); + +return ret; +} + +int psb_mmu_insert_pages (struct psb_mmu_pd *pd,struct page **pages, +unsigned long address,uint32_t num_pages, +uint32_t desired_tile_stride, +uint32_t hw_tile_stride,int type) +{ +struct psb_mmu_pt *pt; +uint32_t rows =1 ; +uint32_t i; +uint32_t pte; +unsigned long addr; +unsigned long end; +unsigned long next; +unsigned long add; +unsigned long row_add; +unsigned long f_address = address; +int ret =0 ; + +if (hw_tile_stride) { +if (num_pages % desired_tile_stride !=0 ) +return -EINVAL ; + rows = num_pages / desired_tile_stride; + }else { + desired_tile_stride = num_pages; + } + + add = desired_tile_stride <<PAGE_SHIFT ; + row_add = hw_tile_stride <<PAGE_SHIFT ; + +down_read (&pd->driver->sem); + +for (i =0 ; i < rows; ++i) { + + addr = address; + end = addr + add; + +do { + next =psb_pd_addr_end (addr, end); + pt =psb_mmu_pt_alloc_map_lock (pd, addr); +if (!pt) { + ret = -ENOMEM ; + goto out; + } +do { + pte = +psb_mmu_mask_pte (page_to_pfn (*pages++), + type); +psb_mmu_set_pte (pt, addr, pte); + pt->count++; + }while (addr +=PAGE_SIZE , addr < next); +psb_mmu_pt_unmap_unlock (pt); + + }while (addr = next, next != end); + + address += row_add; + } +out: +if (pd->hw_context !=-1 ) +psb_mmu_flush_ptes (pd, f_address, num_pages, + desired_tile_stride, hw_tile_stride); + +up_read (&pd->driver->sem); + +if (pd->hw_context !=-1 ) +psb_mmu_flush (pd->driver,1 ); + +return ret; +} + +int psb_mmu_virtual_to_pfn (struct psb_mmu_pd *pd,uint32_t virtual, +unsigned long *pfn) +{ +int ret; +struct psb_mmu_pt *pt; +uint32_t tmp; +spinlock_t *lock = &pd->driver->lock; + +down_read (&pd->driver->sem); + pt =psb_mmu_pt_map_lock (pd, virtual); +if (!pt) { +uint32_t *v; + +spin_lock (lock); + v =kmap_atomic (pd->p,KM_USER0 ); + tmp = v[psb_mmu_pd_index (virtual)]; +kunmap_atomic (v,KM_USER0 ); +spin_unlock (lock); + +if (tmp != pd->invalid_pde || !(tmp &PSB_PTE_VALID ) || + !(pd->invalid_pte &PSB_PTE_VALID )) { + ret = -EINVAL ; + goto out; + } + ret =0 ; + *pfn = pd->invalid_pte >>PAGE_SHIFT ; + goto out; + } + tmp = pt->v[psb_mmu_pt_index (virtual)]; +if (!(tmp &PSB_PTE_VALID )) { + ret = -EINVAL ; + }else { + ret =0 ; + *pfn = tmp >>PAGE_SHIFT ; + } +psb_mmu_pt_unmap_unlock (pt); +out: +up_read (&pd->driver->sem); +return ret; +}_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
Signature · 3 lines
Daniel Vetter Mail: [email protected] Mobile: +41 (0)79 365 57 48
Re: [PATCH 03/12] gma500: introduce the GTT and MMU handling logic
The ioremap for stolen RAM is about 8MB - we do actually need that mapped for the console framebuffer. The GTT tables are pretty small (64K or so) and the rest of the GTT space if ever used doesn't get an ioremap.
It's a bit different to the i915 world because the CPU cannot indirect via the GTT but must go directly.
Quoted 3 lines
Afaik this comment is bogus. And the previous one sounds like it's no clear whether this holds (it does, at least for the i915.ko driver). Maybe kill them both?
Possibly.
Quoted 5 lines
Quoted 5 lines
drivers/gpu/drm/gma500/mmu.c new file +5
-0+static void psb_pages_clflush (struct psb_mmu_driver *driver, +struct page *page[],unsigned long num_pages) +{ +int i; +
Quoted 8 lines
drivers/gpu/drm/gma500/mmu.c line 148
Quoted 6 lines
drivers/gpu/drm/gma500/mmu.c new file +6
-0+if (!driver->has_clflush) +return ; + +for (i =0 ; i < num_pages; i++) +psb_page_clflush (driver, *page++); +}
drm_clflush_pagesdoes that for you.
Ok. Handy to know.
Quoted 3 lines
I my next patch series for i915
drm_cache.cwill grow adrm_clflush_virt_range, which would perfectly fit here. I'll try not to forget gma500 ...
Thanks
Re: [PATCH 03/12] gma500: introduce the GTT and MMU handling logic
Quoted 6 lines · Alan Cox
The ioremap for stolen RAM is about 8MB - we do actually need that mapped for the console framebuffer. The GTT tables are pretty small (64K or so) and the rest of the GTT space if ever used doesn't get an ioremap.
It's a bit different to the i915 world because the CPU cannot indirect via the GTT but must go directly.
Ok, that makes sense. Fyi I'll try to go through the other patches in the coming days, but might take a while.
-Daniel
Signature · 3 lines
Daniel Vetter Mail: [email protected] Mobile: +41 (0)79 365 57 48
PATCH 4/12 gma500: introduce the framebuffer support code
In reply to Alan CoxFrom: Alan Cox <[email protected]>
We support 2D acceleration on some devices but we try and do tricks with the GTT as a starting point as this is far faster. The GTT logic could be improved further but for most display sizes it already makes a pretty good decision.
---
drivers/gpu/drm/gma500/accel_2d.c | 362 ++++++++++++++++ drivers/gpu/drm/gma500/framebuffer.c | 784 ++++++++++++++++++++++++++++++++++ drivers/gpu/drm/gma500/framebuffer.h | 48 ++ 3 files changed, 1194 insertions(+), 0 deletions(-) create mode 100644 drivers/gpu/drm/gma500/accel_2d.c create mode 100644 drivers/gpu/drm/gma500/framebuffer.c create mode 100644 drivers/gpu/drm/gma500/framebuffer.h
drivers/gpu/drm/gma500/accel_2d.c new file +362 -0
@@ -0,0 +1,362 @@ +/************************************************************************** +* Copyright (c) 2007-2011, Intel Corporation. +* All Rights Reserved. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation, Inc., +* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +* +* Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to +* develop this driver. +* +**************************************************************************/ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/tty.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/fb.h> +#include <linux/init.h> +#include <linux/console.h> + +#include <drm/drmP.h> +#include <drm/drm.h> +#include <drm/drm_crtc.h> + +#include "psb_drv.h" +#include "psb_reg.h" +#include "framebuffer.h" + +/** +* psb_spank - reset the 2D engine +* @dev_priv: our PSB DRM device +* +* Soft reset the graphics engine and then reload the necessary registers. +* We use this at initialisation time but it will become relevant for +* accelerated X later +*/ +void psb_spank (struct drm_psb_private *dev_priv) +{ +PSB_WSGX32 (_PSB_CS_RESET_BIF_RESET | _PSB_CS_RESET_DPM_RESET | + _PSB_CS_RESET_TA_RESET | _PSB_CS_RESET_USE_RESET | + _PSB_CS_RESET_ISP_RESET | _PSB_CS_RESET_TSP_RESET | + _PSB_CS_RESET_TWOD_RESET,PSB_CR_SOFT_RESET ); +PSB_RSGX32 (PSB_CR_SOFT_RESET ); + +msleep (1 ); + +PSB_WSGX32 (0 ,PSB_CR_SOFT_RESET ); +wmb (); +PSB_WSGX32 (PSB_RSGX32 (PSB_CR_BIF_CTRL ) | _PSB_CB_CTRL_CLEAR_FAULT, +PSB_CR_BIF_CTRL ); +wmb (); + (void )PSB_RSGX32 (PSB_CR_BIF_CTRL ); + +msleep (1 ); +PSB_WSGX32 (PSB_RSGX32 (PSB_CR_BIF_CTRL ) & ~_PSB_CB_CTRL_CLEAR_FAULT, +PSB_CR_BIF_CTRL ); + (void )PSB_RSGX32 (PSB_CR_BIF_CTRL ); +PSB_WSGX32 (dev_priv->gtt.gatt_start,PSB_CR_BIF_TWOD_REQ_BASE ); +} + +/** +* psb2_2d_wait_available - wait for FIFO room +* @dev_priv: our DRM device +* @size: size (in dwords) of the command we want to issue +* +* Wait until there is room to load the FIFO with our data. If the +* device is not responding then reset it +*/ +static int psb_2d_wait_available (struct drm_psb_private *dev_priv, +unsigned size) +{ +uint32_t avail =PSB_RSGX32 (PSB_CR_2D_SOCIF ); +unsigned long t = jiffies +HZ ; + +while (avail < size) { + avail =PSB_RSGX32 (PSB_CR_2D_SOCIF ); +if (time_after (jiffies, t)) { +psb_spank (dev_priv); +return -EIO ; + } + } +return 0 ; +} + +/** +* psb_2d_submit - submit a 2D command +* @dev_priv: our DRM device +* @cmdbuf: command to issue +* @size: length (in dwords) +* +* Issue one or more 2D commands to the accelerator. This needs to be +* serialized later when we add the GEM interfaces for acceleration +*/ +static int psbfb_2d_submit (struct drm_psb_private *dev_priv,uint32_t *cmdbuf, +unsigned size) +{ +int ret =0 ; +int i; +unsigned submit_size; + +mutex_lock (&dev_priv->mutex_2d); +while (size >0 ) { + submit_size = (size <0x60 ) ? size :0x60 ; + size -= submit_size; + ret =psb_2d_wait_available (dev_priv, submit_size); +if (ret) +break ; + + submit_size <<=2 ; + +for (i =0 ; i < submit_size; i +=4 ) +PSB_WSGX32 (*cmdbuf++,PSB_SGX_2D_SLAVE_PORT + i); + + (void )PSB_RSGX32 (PSB_SGX_2D_SLAVE_PORT + i -4 ); + } +mutex_unlock (&dev_priv->mutex_2d); +return ret; +} + + +/** +* psb_accel_2d_copy_direction - compute blit order +* @xdir: X direction of move +* @ydir: Y direction of move +* +* Compute the correct order setings to ensure that an overlapping blit +* correctly copies all the pixels. +*/ +static u32 psb_accel_2d_copy_direction (int xdir,int ydir) +{ +if (xdir <0 ) +return (ydir <0 ) ?PSB_2D_COPYORDER_BR2TL : +PSB_2D_COPYORDER_TR2BL ; +else +return (ydir <0 ) ?PSB_2D_COPYORDER_BL2TR : +PSB_2D_COPYORDER_TL2BR ; +} + +/** +* psb_accel_2d_copy - accelerated 2D copy +* @dev_priv: our DRM device +* @src_offset in bytes +* @src_stride in bytes +* @src_format psb 2D format defines +* @dst_offset in bytes +* @dst_stride in bytes +* @dst_format psb 2D format defines +* @src_x offset in pixels +* @src_y offset in pixels +* @dst_x offset in pixels +* @dst_y offset in pixels +* @size_x of the copied area +* @size_y of the copied area +* +* Format and issue a 2D accelerated copy command. +*/ +static int psb_accel_2d_copy (struct drm_psb_private *dev_priv, +uint32_t src_offset,uint32_t src_stride, +uint32_t src_format,uint32_t dst_offset, +uint32_t dst_stride,uint32_t dst_format, +uint16_t src_x,uint16_t src_y, +uint16_t dst_x,uint16_t dst_y, +uint16_t size_x,uint16_t size_y) +{ +uint32_t blit_cmd; +uint32_t buffer[10 ]; +uint32_t *buf; +uint32_t direction; + + buf = buffer; + + direction = +psb_accel_2d_copy_direction (src_x - dst_x, src_y - dst_y); + +if (direction ==PSB_2D_COPYORDER_BR2TL || + direction ==PSB_2D_COPYORDER_TR2BL ) { + src_x += size_x -1 ; + dst_x += size_x -1 ; + } +if (direction ==PSB_2D_COPYORDER_BR2TL || + direction ==PSB_2D_COPYORDER_BL2TR ) { + src_y += size_y -1 ; + dst_y += size_y -1 ; + } + + blit_cmd = +PSB_2D_BLIT_BH | +PSB_2D_ROT_NONE | +PSB_2D_DSTCK_DISABLE | +PSB_2D_SRCCK_DISABLE | +PSB_2D_USE_PAT |PSB_2D_ROP3_SRCCOPY | direction; + + *buf++ =PSB_2D_FENCE_BH ; + *buf++ = +PSB_2D_DST_SURF_BH | dst_format | (dst_stride << +PSB_2D_DST_STRIDE_SHIFT ); + *buf++ = dst_offset; + *buf++ = +PSB_2D_SRC_SURF_BH | src_format | (src_stride << +PSB_2D_SRC_STRIDE_SHIFT ); + *buf++ = src_offset; + *buf++ = +PSB_2D_SRC_OFF_BH | (src_x <<PSB_2D_SRCOFF_XSTART_SHIFT ) | + (src_y <<PSB_2D_SRCOFF_YSTART_SHIFT ); + *buf++ = blit_cmd; + *buf++ = + (dst_x <<PSB_2D_DST_XSTART_SHIFT ) | (dst_y << +PSB_2D_DST_YSTART_SHIFT ); + *buf++ = + (size_x <<PSB_2D_DST_XSIZE_SHIFT ) | (size_y << +PSB_2D_DST_YSIZE_SHIFT ); + *buf++ =PSB_2D_FLUSH_BH ; + +return psbfb_2d_submit (dev_priv, buffer, buf - buffer); +} + +/** +* psbfb_copyarea_accel - copyarea acceleration for /dev/fb +* @info: our framebuffer +* @a: copyarea parameters from the framebuffer core +* +* Perform a 2D copy via the accelerator +*/ +static void psbfb_copyarea_accel (struct fb_info *info, +const struct fb_copyarea *a) +{ +struct psb_fbdev *fbdev = info->par; +struct psb_framebuffer *psbfb = &fbdev->pfb; +struct drm_device *dev = psbfb->base.dev; +struct drm_framebuffer *fb = fbdev->psb_fb_helper.fb; +struct drm_psb_private *dev_priv = dev->dev_private; +uint32_t offset; +uint32_t stride; +uint32_t src_format; +uint32_t dst_format; + +if (!fb) +return ; + + offset = psbfb->gtt->offset; + stride = fb->pitch; + +switch (fb->depth) { +case 8 : + src_format =PSB_2D_SRC_332RGB ; + dst_format =PSB_2D_DST_332RGB ; +break ; +case 15 : + src_format =PSB_2D_SRC_555RGB ; + dst_format =PSB_2D_DST_555RGB ; +break ; +case 16 : + src_format =PSB_2D_SRC_565RGB ; + dst_format =PSB_2D_DST_565RGB ; +break ; +case 24 : +case 32 : +/* this is wrong but since we don't do blending its okay */ + src_format =PSB_2D_SRC_8888ARGB ; + dst_format =PSB_2D_DST_8888ARGB ; +break ; +default : +/* software fallback */ +cfb_copyarea (info, a); +return ; + } + +if (!gma_power_begin (dev, false)) { +cfb_copyarea (info, a); +return ; + } +psb_accel_2d_copy (dev_priv, + offset, stride, src_format, + offset, stride, dst_format, + a->sx, a->sy, a->dx, a->dy, a->width, a->height); +gma_power_end (dev); +} + +/** +* psbfb_copyarea - 2D copy interface +* @info: our framebuffer +* @region: region to copy +* +* Copy an area of the framebuffer console either by the accelerator +* or directly using the cfb helpers according to the request +*/ +void psbfb_copyarea (struct fb_info *info, +const struct fb_copyarea *region) +{ +if (unlikely (info->state !=FBINFO_STATE_RUNNING )) +return ; + +/* Avoid the 8 pixel erratum */ +if (region->width ==8 || region->height ==8 || + (info->flags &FBINFO_HWACCEL_DISABLED )) +return cfb_copyarea (info, region); + +psbfb_copyarea_accel (info, region); +} + +/** +* psbfb_sync - synchronize 2D +* @info: our framebuffer +* +* Wait for the 2D engine to quiesce so that we can do CPU +* access to the framebuffer again +*/ +int psbfb_sync (struct fb_info *info) +{ +struct psb_fbdev *fbdev = info->par; +struct psb_framebuffer *psbfb = &fbdev->pfb; +struct drm_device *dev = psbfb->base.dev; +struct drm_psb_private *dev_priv = dev->dev_private; +unsigned long _end = jiffies +DRM_HZ ; +int busy =0 ; + +mutex_lock (&dev_priv->mutex_2d); +/* +* First idle the 2D engine. +*/ + +if ((PSB_RSGX32 (PSB_CR_2D_SOCIF ) == _PSB_C2_SOCIF_EMPTY) && + ((PSB_RSGX32 (PSB_CR_2D_BLIT_STATUS ) & _PSB_C2B_STATUS_BUSY) ==0 )) + goto out; + +do { + busy = (PSB_RSGX32 (PSB_CR_2D_SOCIF ) != _PSB_C2_SOCIF_EMPTY); +cpu_relax (); + }while (busy && !time_after_eq (jiffies, _end)); + +if (busy) + busy = (PSB_RSGX32 (PSB_CR_2D_SOCIF ) != _PSB_C2_SOCIF_EMPTY); +if (busy) + goto out; + +do { + busy = ((PSB_RSGX32 (PSB_CR_2D_BLIT_STATUS ) & + _PSB_C2B_STATUS_BUSY) !=0 ); +cpu_relax (); + }while (busy && !time_after_eq (jiffies, _end)); +if (busy) + busy = ((PSB_RSGX32 (PSB_CR_2D_BLIT_STATUS ) & + _PSB_C2B_STATUS_BUSY) !=0 ); + +out: +mutex_unlock (&dev_priv->mutex_2d); +return (busy) ? -EBUSY :0 ; +}
drivers/gpu/drm/gma500/framebuffer.c new file +784 -0
784 lines not on this page · raw message
drivers/gpu/drm/gma500/framebuffer.h new file +48 -0
48 lines not on this page · raw message
PATCH 5/12 gma500: Add device framework
In reply to Alan CoxFrom: Alan Cox <[email protected]>
The devices have various internal differences so we have some abstractions to hide the ugly differences and we then wrap them up in standard interfaces. Add these bits
---
drivers/gpu/drm/gma500/backlight.c | 49 ++++++ drivers/gpu/drm/gma500/power.c | 316 ++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/gma500/power.h | 67 ++++++++ 3 files changed, 432 insertions(+), 0 deletions(-) create mode 100644 drivers/gpu/drm/gma500/backlight.c create mode 100644 drivers/gpu/drm/gma500/power.c create mode 100644 drivers/gpu/drm/gma500/power.h
drivers/gpu/drm/gma500/backlight.c new file +49 -0
@@ -0,0 +1,49 @@ +/* +* GMA500 Backlight Interface +* +* Copyright (c) 2009-2011, Intel Corporation. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation, Inc., +* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +* +* Authors: Eric Knopp +* +*/ + +#include "psb_drv.h" +#include "psb_intel_reg.h" +#include "psb_intel_drv.h" +#include "intel_bios.h" +#include "power.h" + +int gma_backlight_init (struct drm_device *dev) +{ +#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE +struct drm_psb_private *dev_priv = dev->dev_private; +return dev_priv->ops->backlight_init (dev); +#else +return 0 ; +#endif +} + +void gma_backlight_exit (struct drm_device *dev) +{ +#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE +struct drm_psb_private *dev_priv = dev->dev_private; +if (dev_priv->backlight_device) { + dev_priv->backlight_device->props.brightness =0 ; +backlight_update_status (dev_priv->backlight_device); +backlight_device_unregister (dev_priv->backlight_device); + } +#endif +}
drivers/gpu/drm/gma500/power.c new file +316 -0
316 lines not on this page · raw message
drivers/gpu/drm/gma500/power.h new file +67 -0
67 lines not on this page · raw message
PATCH 6/12 gma500: Add the glue to the various BIOS and firmware interfaces
In reply to Alan CoxFrom: Alan Cox <[email protected]>
Some of this should one day become a library shared by i915 and gma500 I suspct. Best however to deal with that later once it is all nice and stably merged.
---
drivers/gpu/drm/gma500/intel_bios.c | 303 ++++++++++++++++++++++ drivers/gpu/drm/gma500/intel_bios.h | 430 +++++++++++++++++++++++++++++++ drivers/gpu/drm/gma500/intel_opregion.c | 80 ++++++ drivers/gpu/drm/gma500/mid_bios.c | 243 ++++++++++++++++++ drivers/gpu/drm/gma500/mid_bios.h | 21 ++ 5 files changed, 1077 insertions(+), 0 deletions(-) create mode 100644 drivers/gpu/drm/gma500/intel_bios.c create mode 100644 drivers/gpu/drm/gma500/intel_bios.h create mode 100644 drivers/gpu/drm/gma500/intel_opregion.c create mode 100644 drivers/gpu/drm/gma500/mid_bios.c create mode 100644 drivers/gpu/drm/gma500/mid_bios.h
drivers/gpu/drm/gma500/intel_bios.c new file +303 -0
@@ -0,0 +1,303 @@ +/* +* Copyright (c) 2006 Intel Corporation +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation, Inc., +* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +* +* Authors: +* Eric Anholt <[email protected]> +* +*/ +#include <drm/drmP.h> +#include <drm/drm.h> +#include "psb_drm.h" +#include "psb_drv.h" +#include "psb_intel_drv.h" +#include "psb_intel_reg.h" +#include "intel_bios.h" + + +static void *find_section (struct bdb_header *bdb,int section_id) +{ +u8 *base = (u8 *)bdb; +int index =0 ; +u16 total, current_size; +u8 current_id; + +/* skip to first section */ + index += bdb->header_size; + total = bdb->bdb_size; + +/* walk the sections looking for section_id */ +while (index < total) { + current_id = *(base + index); + index++; + current_size = *((u16 *)(base + index)); + index +=2 ; +if (current_id == section_id) +return base + index; + index += current_size; + } + +return NULL ; +} + +static void fill_detail_timing_data (struct drm_display_mode *panel_fixed_mode, +struct lvds_dvo_timing *dvo_timing) +{ + panel_fixed_mode->hdisplay = (dvo_timing->hactive_hi <<8 ) | + dvo_timing->hactive_lo; + panel_fixed_mode->hsync_start = panel_fixed_mode->hdisplay + + ((dvo_timing->hsync_off_hi <<8 ) | dvo_timing->hsync_off_lo); + panel_fixed_mode->hsync_end = panel_fixed_mode->hsync_start + + dvo_timing->hsync_pulse_width; + panel_fixed_mode->htotal = panel_fixed_mode->hdisplay + + ((dvo_timing->hblank_hi <<8 ) | dvo_timing->hblank_lo); + + panel_fixed_mode->vdisplay = (dvo_timing->vactive_hi <<8 ) | + dvo_timing->vactive_lo; + panel_fixed_mode->vsync_start = panel_fixed_mode->vdisplay + + dvo_timing->vsync_off; + panel_fixed_mode->vsync_end = panel_fixed_mode->vsync_start + + dvo_timing->vsync_pulse_width; + panel_fixed_mode->vtotal = panel_fixed_mode->vdisplay + + ((dvo_timing->vblank_hi <<8 ) | dvo_timing->vblank_lo); + panel_fixed_mode->clock = dvo_timing->clock *10 ; + panel_fixed_mode->type =DRM_MODE_TYPE_PREFERRED ; + +/* Some VBTs have bogus h/vtotal values */ +if (panel_fixed_mode->hsync_end > panel_fixed_mode->htotal) + panel_fixed_mode->htotal = panel_fixed_mode->hsync_end +1 ; +if (panel_fixed_mode->vsync_end > panel_fixed_mode->vtotal) + panel_fixed_mode->vtotal = panel_fixed_mode->vsync_end +1 ; + +drm_mode_set_name (panel_fixed_mode); +} + +static void parse_backlight_data (struct drm_psb_private *dev_priv, +struct bdb_header *bdb) +{ +struct bdb_lvds_backlight *vbt_lvds_bl =NULL ; +struct bdb_lvds_backlight *lvds_bl; +u8 p_type =0 ; +void *bl_start =NULL ; +struct bdb_lvds_options *lvds_opts + =find_section (bdb,BDB_LVDS_OPTIONS ); + + dev_priv->lvds_bl =NULL ; + +if (lvds_opts) + p_type = lvds_opts->panel_type; +else +return ; + + bl_start =find_section (bdb,BDB_LVDS_BACKLIGHT ); + vbt_lvds_bl = (struct bdb_lvds_backlight *)(bl_start +1 ) + p_type; + + lvds_bl =kzalloc (sizeof (*vbt_lvds_bl),GFP_KERNEL ); +if (!lvds_bl) { +dev_err (dev_priv->dev->dev,"out of memory for backlight data\n" ); +return ; + } +memcpy (lvds_bl, vbt_lvds_bl,sizeof (*vbt_lvds_bl)); + dev_priv->lvds_bl = lvds_bl; +} + +/* Try to find integrated panel data */ +static void parse_lfp_panel_data (struct drm_psb_private *dev_priv, +struct bdb_header *bdb) +{ +struct bdb_lvds_options *lvds_options; +struct bdb_lvds_lfp_data *lvds_lfp_data; +struct bdb_lvds_lfp_data_entry *entry; +struct lvds_dvo_timing *dvo_timing; +struct drm_display_mode *panel_fixed_mode; + +/* Defaults if we can't find VBT info */ + dev_priv->lvds_dither =0 ; + dev_priv->lvds_vbt =0 ; + + lvds_options =find_section (bdb,BDB_LVDS_OPTIONS ); +if (!lvds_options) +return ; + + dev_priv->lvds_dither = lvds_options->pixel_dither; +if (lvds_options->panel_type ==0xff ) +return ; + + lvds_lfp_data =find_section (bdb,BDB_LVDS_LFP_DATA ); +if (!lvds_lfp_data) +return ; + + + entry = &lvds_lfp_data->data[lvds_options->panel_type]; + dvo_timing = &entry->dvo_timing; + + panel_fixed_mode =kzalloc (sizeof (*panel_fixed_mode), +GFP_KERNEL ); +if (panel_fixed_mode ==NULL ) { +dev_err (dev_priv->dev->dev,"out of memory for fixed panel mode\n" ); +return ; + } + + dev_priv->lvds_vbt =1 ; +fill_detail_timing_data (panel_fixed_mode, dvo_timing); + +if (panel_fixed_mode->htotal >0 && panel_fixed_mode->vtotal >0 ) { + dev_priv->lfp_lvds_vbt_mode = panel_fixed_mode; +drm_mode_debug_printmodeline (panel_fixed_mode); + }else { +dev_dbg (dev_priv->dev->dev,"ignoring invalid LVDS VBT\n" ); + dev_priv->lvds_vbt =0 ; +kfree (panel_fixed_mode); + } +return ; +} + +/* Try to find sdvo panel data */ +static void parse_sdvo_panel_data (struct drm_psb_private *dev_priv, +struct bdb_header *bdb) +{ +struct bdb_sdvo_lvds_options *sdvo_lvds_options; +struct lvds_dvo_timing *dvo_timing; +struct drm_display_mode *panel_fixed_mode; + + dev_priv->sdvo_lvds_vbt_mode =NULL ; + + sdvo_lvds_options =find_section (bdb,BDB_SDVO_LVDS_OPTIONS ); +if (!sdvo_lvds_options) +return ; + + dvo_timing =find_section (bdb,BDB_SDVO_PANEL_DTDS ); +if (!dvo_timing) +return ; + + panel_fixed_mode =kzalloc (sizeof (*panel_fixed_mode),GFP_KERNEL ); + +if (!panel_fixed_mode) +return ; + +fill_detail_timing_data (panel_fixed_mode, + dvo_timing + sdvo_lvds_options->panel_type); + + dev_priv->sdvo_lvds_vbt_mode = panel_fixed_mode; + +return ; +} + +static void parse_general_features (struct drm_psb_private *dev_priv, +struct bdb_header *bdb) +{ +struct bdb_general_features *general; + +/* Set sensible defaults in case we can't find the general block */ + dev_priv->int_tv_support =1 ; + dev_priv->int_crt_support =1 ; + + general =find_section (bdb,BDB_GENERAL_FEATURES ); +if (general) { + dev_priv->int_tv_support = general->int_tv_support; + dev_priv->int_crt_support = general->int_crt_support; + dev_priv->lvds_use_ssc = general->enable_ssc; + +if (dev_priv->lvds_use_ssc) { + dev_priv->lvds_ssc_freq + = general->ssc_freq ?100 :96 ; + } + } +} + +/** +* psb_intel_init_bios - initialize VBIOS settings & find VBT +* @dev: DRM device +* +* Loads the Video BIOS and checks that the VBT exists. Sets scratch registers +* to appropriate values. +* +* VBT existence is a sanity check that is relied on by other i830_bios.c code. +* Note that it would be better to use a BIOS call to get the VBT, as BIOSes may +* feed an updated VBT back through that, compared to what we'll fetch using +* this method of groping around in the BIOS data. +* +* Returns 0 on success, nonzero on failure. +*/ +bool psb_intel_init_bios (struct drm_device *dev) +{ +struct drm_psb_private *dev_priv = dev->dev_private; +struct pci_dev *pdev = dev->pdev; +struct vbt_header *vbt =NULL ; +struct bdb_header *bdb; +u8 __iomem *bios; +size_t size; +int i; + + bios =pci_map_rom (pdev, &size); +if (!bios) +return -1 ; + +/* Scour memory looking for the VBT signature */ +for (i =0 ; i +4 < size; i++) { +if (!memcmp (bios + i,"$VBT" ,4 )) { + vbt = (struct vbt_header *)(bios + i); +break ; + } + } + +if (!vbt) { +dev_err (dev->dev,"VBT signature missing\n" ); +pci_unmap_rom (pdev, bios); +return -1 ; + } + + bdb = (struct bdb_header *)(bios + i + vbt->bdb_offset); + +/* Grab useful general definitions */ +parse_general_features (dev_priv, bdb); +parse_lfp_panel_data (dev_priv, bdb); +parse_sdvo_panel_data (dev_priv, bdb); +parse_backlight_data (dev_priv, bdb); + +pci_unmap_rom (pdev, bios); + +return 0 ; +} + +/** +* Destroy and free VBT data +*/ +void psb_intel_destroy_bios (struct drm_device *dev) +{ +struct drm_psb_private *dev_priv = dev->dev_private; +struct drm_display_mode *sdvo_lvds_vbt_mode = + dev_priv->sdvo_lvds_vbt_mode; +struct drm_display_mode *lfp_lvds_vbt_mode = + dev_priv->lfp_lvds_vbt_mode; +struct bdb_lvds_backlight *lvds_bl = + dev_priv->lvds_bl; + +/*free sdvo panel mode*/ +if (sdvo_lvds_vbt_mode) { + dev_priv->sdvo_lvds_vbt_mode =NULL ; +kfree (sdvo_lvds_vbt_mode); + } + +if (lfp_lvds_vbt_mode) { + dev_priv->lfp_lvds_vbt_mode =NULL ; +kfree (lfp_lvds_vbt_mode); + } + +if (lvds_bl) { + dev_priv->lvds_bl =NULL ; +kfree (lvds_bl); + } +}
drivers/gpu/drm/gma500/intel_bios.h new file +430 -0
430 lines not on this page · raw message
drivers/gpu/drm/gma500/intel_opregion.c new file +80 -0
80 lines not on this page · raw message
drivers/gpu/drm/gma500/mid_bios.c new file +243 -0
243 lines not on this page · raw message
drivers/gpu/drm/gma500/mid_bios.h new file +21 -0
@@ -0,0 +1,21 @@ +/************************************************************************** +* Copyright (c) 2011, Intel Corporation. +* All Rights Reserved. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation, Inc., +* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +* +**************************************************************************/ + +extern int mid_chip_setup (struct drm_device *dev); +
PATCH 7/12 gma500: Add the i2c bus support
In reply to Alan CoxFrom: Alan Cox <[email protected]>
Again this might be a candidate for sharing later.
---
drivers/gpu/drm/gma500/intel_i2c.c | 169 ++++++++++++++++++++++++++++++++++++ 1 files changed, 169 insertions(+), 0 deletions(-) create mode 100644 drivers/gpu/drm/gma500/intel_i2c.c
drivers/gpu/drm/gma500/intel_i2c.c new file +169 -0
@@ -0,0 +1,169 @@ +/* +* Copyright © 2006-2007 Intel Corporation +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation, Inc., +* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +* +* Authors: +* Eric Anholt <[email protected]> +*/ + +#include <linux/i2c.h> +#include <linux/i2c-algo-bit.h> + +#include "psb_drv.h" +#include "psb_intel_reg.h" + +/* +* Intel GPIO access functions +*/ + +#define I2C_RISEFALL_TIME 20 + +static int get_clock (void *data) +{ +struct psb_intel_i2c_chan *chan = data; +struct drm_device *dev = chan->drm_dev; +u32 val; + + val =REG_READ (chan->reg); +return (val &GPIO_CLOCK_VAL_IN ) !=0 ; +} + +static int get_data (void *data) +{ +struct psb_intel_i2c_chan *chan = data; +struct drm_device *dev = chan->drm_dev; +u32 val; + + val =REG_READ (chan->reg); +return (val &GPIO_DATA_VAL_IN ) !=0 ; +} + +static void set_clock (void *data,int state_high) +{ +struct psb_intel_i2c_chan *chan = data; +struct drm_device *dev = chan->drm_dev; +u32 reserved =0 , clock_bits; + +/* On most chips, these bits must be preserved in software. */ + reserved = +REG_READ (chan->reg) & (GPIO_DATA_PULLUP_DISABLE | +GPIO_CLOCK_PULLUP_DISABLE ); + +if (state_high) + clock_bits =GPIO_CLOCK_DIR_IN |GPIO_CLOCK_DIR_MASK ; +else + clock_bits =GPIO_CLOCK_DIR_OUT |GPIO_CLOCK_DIR_MASK | +GPIO_CLOCK_VAL_MASK ; +REG_WRITE (chan->reg, reserved | clock_bits); +udelay (I2C_RISEFALL_TIME );/* wait for the line to change state */ +} + +static void set_data (void *data,int state_high) +{ +struct psb_intel_i2c_chan *chan = data; +struct drm_device *dev = chan->drm_dev; +u32 reserved =0 , data_bits; + +/* On most chips, these bits must be preserved in software. */ + reserved = +REG_READ (chan->reg) & (GPIO_DATA_PULLUP_DISABLE | +GPIO_CLOCK_PULLUP_DISABLE ); + +if (state_high) + data_bits =GPIO_DATA_DIR_IN |GPIO_DATA_DIR_MASK ; +else + data_bits = +GPIO_DATA_DIR_OUT |GPIO_DATA_DIR_MASK | +GPIO_DATA_VAL_MASK ; + +REG_WRITE (chan->reg, reserved | data_bits); +udelay (I2C_RISEFALL_TIME );/* wait for the line to change state */ +} + +/** +* psb_intel_i2c_create - instantiate an Intel i2c bus using the specified GPIO reg +* @dev: DRM device +* @output: driver specific output device +* @reg: GPIO reg to use +* @name: name for this bus +* +* Creates and registers a new i2c bus with the Linux i2c layer, for use +* in output probing and control (e.g. DDC or SDVO control functions). +* +* Possible values for @reg include: +* %GPIOA +* %GPIOB +* %GPIOC +* %GPIOD +* %GPIOE +* %GPIOF +* %GPIOG +* %GPIOH +* see PRM for details on how these different busses are used. +*/ +struct psb_intel_i2c_chan *psb_intel_i2c_create (struct drm_device *dev, +const u32 reg,const char *name) +{ +struct psb_intel_i2c_chan *chan; + + chan =kzalloc (sizeof (struct psb_intel_i2c_chan ),GFP_KERNEL ); +if (!chan) + goto out_free; + + chan->drm_dev = dev; + chan->reg = reg; +snprintf (chan->adapter.name,I2C_NAME_SIZE ,"intel drm %s" , name); + chan->adapter.owner =THIS_MODULE ; + chan->adapter.algo_data = &chan->algo; + chan->adapter.dev.parent = &dev->pdev->dev; + chan->algo.setsda = set_data; + chan->algo.setscl = set_clock; + chan->algo.getsda = get_data; + chan->algo.getscl = get_clock; + chan->algo.udelay =20 ; + chan->algo.timeout =usecs_to_jiffies (2200 ); + chan->algo.data = chan; + +i2c_set_adapdata (&chan->adapter, chan); + +if (i2c_bit_add_bus (&chan->adapter)) + goto out_free; + +/* JJJ: raise SCL and SDA? */ +set_data (chan,1 ); +set_clock (chan,1 ); +udelay (20 ); + +return chan; + +out_free: +kfree (chan); +return NULL ; +} + +/** +* psb_intel_i2c_destroy - unregister and free i2c bus resources +* @output: channel to free +* +* Unregister the adapter from the i2c layer, then free the structure. +*/ +void psb_intel_i2c_destroy (struct psb_intel_i2c_chan *chan) +{ +if (!chan) +return ; + +i2c_del_adapter (&chan->adapter); +kfree (chan); +}
_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
PATCH 8/12 gma500: Add the core DRM files and headers
In reply to Alan CoxFrom: Alan Cox <[email protected]>
Not really a nice way to split this up further for submission. This provides all the DRM interfacing logic, the headers and relevant glue.
---
drivers/gpu/drm/gma500/psb_drm.h | 207 +++++++ drivers/gpu/drm/gma500/psb_drv.c | 1210 ++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/gma500/psb_drv.h | 924 +++++++++++++++++++++++++++++ drivers/gpu/drm/gma500/psb_irq.c | 553 +++++++++++++++++ drivers/gpu/drm/gma500/psb_irq.h | 45 + drivers/gpu/drm/gma500/psb_reg.h | 582 ++++++++++++++++++ 6 files changed, 3521 insertions(+), 0 deletions(-) create mode 100644 drivers/gpu/drm/gma500/psb_drm.h create mode 100644 drivers/gpu/drm/gma500/psb_drv.c create mode 100644 drivers/gpu/drm/gma500/psb_drv.h create mode 100644 drivers/gpu/drm/gma500/psb_irq.c create mode 100644 drivers/gpu/drm/gma500/psb_irq.h create mode 100644 drivers/gpu/drm/gma500/psb_reg.h
drivers/gpu/drm/gma500/psb_drm.h new file +207 -0
@@ -0,0 +1,207 @@ +/************************************************************************** +* Copyright (c) 2007-2011, Intel Corporation. +* All Rights Reserved. +* Copyright (c) 2008, Tungsten Graphics Inc. Cedar Park, TX., USA. +* All Rights Reserved. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation, Inc., +* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +* +**************************************************************************/ + +#ifndef _PSB_DRM_H_ +#define _PSB_DRM_H_ + +#define PSB_NUM_PIPE 3 + +#define PSB_GPU_ACCESS_READ (1ULL << 32) +#define PSB_GPU_ACCESS_WRITE (1ULL << 33) +#define PSB_GPU_ACCESS_MASK (PSB_GPU_ACCESS_READ | PSB_GPU_ACCESS_WRITE) + +#define PSB_BO_FLAG_COMMAND (1ULL << 52) + +/* +* Feedback components: +*/ + +struct drm_psb_sizes_arg { +u32 ta_mem_size; +u32 mmu_size; +u32 pds_size; +u32 rastgeom_size; +u32 tt_size; +u32 vram_size; +}; + +struct drm_psb_dpst_lut_arg { +uint8_t lut[256 ]; +int output_id; +}; + +#define PSB_DC_CRTC_SAVE 0x01 +#define PSB_DC_CRTC_RESTORE 0x02 +#define PSB_DC_OUTPUT_SAVE 0x04 +#define PSB_DC_OUTPUT_RESTORE 0x08 +#define PSB_DC_CRTC_MASK 0x03 +#define PSB_DC_OUTPUT_MASK 0x0C + +struct drm_psb_dc_state_arg { +u32 flags; +u32 obj_id; +}; + +struct drm_psb_mode_operation_arg { +u32 obj_id; +u16 operation; +struct drm_mode_modeinfo mode; +void *data; +}; + +struct drm_psb_stolen_memory_arg { +u32 base; +u32 size; +}; + +/*Display Register Bits*/ +#define REGRWBITS_PFIT_CONTROLS (1 << 0) +#define REGRWBITS_PFIT_AUTOSCALE_RATIOS (1 << 1) +#define REGRWBITS_PFIT_PROGRAMMED_SCALE_RATIOS (1 << 2) +#define REGRWBITS_PIPEASRC (1 << 3) +#define REGRWBITS_PIPEBSRC (1 << 4) +#define REGRWBITS_VTOTAL_A (1 << 5) +#define REGRWBITS_VTOTAL_B (1 << 6) +#define REGRWBITS_DSPACNTR (1 << 8) +#define REGRWBITS_DSPBCNTR (1 << 9) +#define REGRWBITS_DSPCCNTR (1 << 10) + +/*Overlay Register Bits*/ +#define OV_REGRWBITS_OVADD (1 << 0) +#define OV_REGRWBITS_OGAM_ALL (1 << 1) + +#define OVC_REGRWBITS_OVADD (1 << 2) +#define OVC_REGRWBITS_OGAM_ALL (1 << 3) + +struct drm_psb_register_rw_arg { +u32 b_force_hw_on; + +u32 display_read_mask; +u32 display_write_mask; + +struct { +u32 pfit_controls; +u32 pfit_autoscale_ratios; +u32 pfit_programmed_scale_ratios; +u32 pipeasrc; +u32 pipebsrc; +u32 vtotal_a; +u32 vtotal_b; + } display; + +u32 overlay_read_mask; +u32 overlay_write_mask; + +struct { +u32 OVADD; +u32 OGAMC0; +u32 OGAMC1; +u32 OGAMC2; +u32 OGAMC3; +u32 OGAMC4; +u32 OGAMC5; +u32 IEP_ENABLED; +u32 IEP_BLE_MINMAX; +u32 IEP_BSSCC_CONTROL; +u32 b_wait_vblank; + } overlay; + +u32 sprite_enable_mask; +u32 sprite_disable_mask; + +struct { +u32 dspa_control; +u32 dspa_key_value; +u32 dspa_key_mask; +u32 dspc_control; +u32 dspc_stride; +u32 dspc_position; +u32 dspc_linear_offset; +u32 dspc_size; +u32 dspc_surface; + } sprite; + +u32 subpicture_enable_mask; +u32 subpicture_disable_mask; +}; + +/* Controlling the kernel modesetting buffers */ + +#define DRM_PSB_SIZES 0x07 +#define DRM_PSB_FUSE_REG 0x08 +#define DRM_PSB_DC_STATE 0x0A +#define DRM_PSB_ADB 0x0B +#define DRM_PSB_MODE_OPERATION 0x0C +#define DRM_PSB_STOLEN_MEMORY 0x0D +#define DRM_PSB_REGISTER_RW 0x0E + +/* +* NOTE: Add new commands here, but increment +* the values below and increment their +* corresponding defines where they're +* defined elsewhere. +*/ + +#define DRM_PSB_GEM_CREATE 0x10 +#define DRM_PSB_2D_OP 0x11/* Will be merged later */ +#define DRM_PSB_GEM_MMAP 0x12 +#define DRM_PSB_DPST 0x1B +#define DRM_PSB_GAMMA 0x1C +#define DRM_PSB_DPST_BL 0x1D +#define DRM_PSB_GET_PIPE_FROM_CRTC_ID 0x1F + +#define PSB_MODE_OPERATION_MODE_VALID 0x01 +#define PSB_MODE_OPERATION_SET_DC_BASE 0x02 + +struct drm_psb_get_pipe_from_crtc_id_arg { +/** ID of CRTC being requested **/ +u32 crtc_id; + +/** pipe of requested CRTC **/ +u32 pipe; +}; + +/* FIXME: move this into a medfield header once we are sure it isn't needed for an +ioctl */ +struct psb_drm_dpu_rect { +int x, y; +int width, height; +}; + +struct drm_psb_gem_create { +__u64 size; +__u32 handle; +__u32 flags; +#define PSB_GEM_CREATE_STOLEN 1/* Stolen memory can be used */ +}; + +struct drm_psb_gem_mmap { +__u32 handle; +__u32 pad; +/** +* Fake offset to use for subsequent mmap call +* +* This is a fixed-size type for 32/64 compatibility. +*/ +__u64 offset; +}; + +#endif
drivers/gpu/drm/gma500/psb_drv.c new file +1210 -0
1,210 lines not on this page · raw message
drivers/gpu/drm/gma500/psb_drv.h new file +924 -0
924 lines not on this page · raw message
drivers/gpu/drm/gma500/psb_irq.c new file +553 -0
553 lines not on this page · raw message
drivers/gpu/drm/gma500/psb_irq.h new file +45 -0
45 lines not on this page · raw message
drivers/gpu/drm/gma500/psb_reg.h new file +582 -0
61 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Part of the diff is not shown here. View the raw message.
Dave Airlie
maintainerRe: [PATCH 08/12] gma500: Add the core DRM files and headers
Quoted 4 lines · Alan Cox
From: Alan Cox <[email protected]>
Not really a nice way to split this up further for submission. This provides all the DRM interfacing logic, the headers and relevant glue.
I've started merging it, and my main review focus is as always the userspace interfaces, which we are now setting in stone for ever (or 5-10 years whichever is shorter).
So generally we need to provide a userspace interface via ioctls, we do this with a shared header file that goes in include/drm/ with the Kbuild bits
Now I'm assuming psb_drm.h is meant to be this file? but as-is its not really what I'd expect,
If you look at radeon you'll see defines for device specific ioctls, same for i915, now I note these tables start at 0 and work their way up,
Now if I understand the holes in this are due to some old userspace code that is probably broken anyway,
It might be worth renaming psb_drm.h to gma500_drm.h to reflect the overall driver name and then maybe start with a clean interface, I'm willing to listen to why this is a bad plan, but I'd rather not push psb_drm.h into kernel header packages and libdrm if there is a conflicting one in existance (or conflicting 6).
some more comments below,
drivers/gpu/drm/gma500/psb_drm.h line 31
Quoted 5 lines
drivers/gpu/drm/gma500/psb_drm.h new file +5
-0+#define PSB_GPU_ACCESS_READ (1ULL << 32) +#define PSB_GPU_ACCESS_WRITE (1ULL << 33) +#define PSB_GPU_ACCESS_MASK (PSB_GPU_ACCESS_READ | PSB_GPU_ACCESS_WRITE) + +#define PSB_BO_FLAG_COMMAND (1ULL << 52)
Any reason it start at 52?
drivers/gpu/drm/gma500/psb_drm.h line 68
Quoted 6 lines
drivers/gpu/drm/gma500/psb_drm.h new file +6
-0+struct drm_psb_mode_operation_arg { + u32 obj_id; + u16 operation; + struct drm_mode_modeinfo mode; + void *data; +};
No void * in ioctl args, no u16 in ioctls args, not really sure what a mode "operation" is here either. Try and design the ioctls to avoid compat wrapper requirements.
Maybe move the operation flags up here.
drivers/gpu/drm/gma500/psb_drm.h line 73
Quoted 5 lines
drivers/gpu/drm/gma500/psb_drm.h new file +5
-0+ +struct drm_psb_stolen_memory_arg { + u32 base; + u32 size; +};
Why does someone care about this? is it a workaround for lack of decent memory management?
drivers/gpu/drm/gma500/psb_drm.h line 154
Quoted 9 lines
drivers/gpu/drm/gma500/psb_drm.h new file +9
-0+/* Controlling the kernel modesetting buffers */ + +#define DRM_PSB_SIZES 0x07 +#define DRM_PSB_FUSE_REG 0x08 +#define DRM_PSB_DC_STATE 0x0A +#define DRM_PSB_ADB 0x0B +#define DRM_PSB_MODE_OPERATION 0x0C +#define DRM_PSB_STOLEN_MEMORY 0x0D +#define DRM_PSB_REGISTER_RW 0x0E
Direct read/writing of registers is not something, the regs being hit here seem like workarounds for not having good overlay support in the kernel perhaps,
can the new plane stuff help workaround this?
drivers/gpu/drm/gma500/psb_drm.h line 169
Quoted 7 lines
drivers/gpu/drm/gma500/psb_drm.h new file +7
-0+#define DRM_PSB_GEM_CREATE 0x10 +#define DRM_PSB_2D_OP 0x11/* Will be merged later */ +#define DRM_PSB_GEM_MMAP 0x12 +#define DRM_PSB_DPST 0x1B +#define DRM_PSB_GAMMA 0x1C +#define DRM_PSB_DPST_BL 0x1D +#define DRM_PSB_GET_PIPE_FROM_CRTC_ID 0x1F
If these are compat with somewhere else please state where the master database is kept so future people can avoid collisions with closed source drivers.
drivers/gpu/drm/gma500/psb_drm.h line 180
Quoted 11 lines
drivers/gpu/drm/gma500/psb_drm.h new file +11
-0+ +#define PSB_MODE_OPERATION_MODE_VALID 0x01 +#define PSB_MODE_OPERATION_SET_DC_BASE 0x02 + +struct drm_psb_get_pipe_from_crtc_id_arg { + /** ID of CRTC being requested **/ + u32 crtc_id; + + /** pipe of requested CRTC **/ + u32 pipe; +};
I'm happy that we can fix all these problems incrementally with patches on top of these, as I take the notion that the userspace ioctls aren't set in stone until Linus merges and does a release containing them.
So you can probably considered these patches merged at least, I'll just keep them in a topic branch which I'll stick into the drm-next queue.
Dave.
Re: [PATCH 08/12] gma500: Add the core DRM files and headers
Quoted 3 lines
So generally we need to provide a userspace interface via ioctls, we do this with a shared header file that goes in
include/drm/with theKbuildbits
At the moment the only public API is the generic bits.
Quoted 2 lines
Now I'm assuming
psb_drm.his meant to be this file? but as-is its not really what I'd expect,
Not yet.
Quoted 3 lines
If you look at radeon you'll see defines for device specific ioctls, same for i915, now I note these tables start at 0 and work their way up,
I'll move the ones we want to zero.
Quoted 2 lines
Now if I understand the holes in this are due to some old userspace code that is probably broken anyway,
Yep.. but really I can kill them off. The total number of people affected will be < 10.
Quoted 3 lines
willing to listen to why this is a bad plan, but I'd rather not push
psb_drm.hinto kernel header packages and libdrm if there is a conflicting one in existance (or conflicting 6).
Last time I looked there were conflicts between the various IMG based Intel ones let along with anything else - lost cause so we might as well do it right.
We could use a new namespace that might be smarter in fact.
Quoted 3 lines
Quoted 1 line
+#define
PSB_BO_FLAG_COMMAND(1ULL << 52)Any reason it start at 52?
That may be obsolete
Quoted 12 lines
drivers/gpu/drm/gma500/psb_drm.h line 68
Quoted 7 lines
drivers/gpu/drm/gma500/psb_drm.h new file +6
-0+struct drm_psb_mode_operation_arg { + u32 obj_id; + u16 operation; + struct drm_mode_modeinfo mode; + void *data; +};No void * in ioctl args, no u16 in ioctls args, not really sure what a mode "operation" is here either. Try and design the ioctls to avoid compat wrapper requirements.
Maybe move the operation flags up here.
Again I need to see if we can simply kill it off
Quoted 8 lines
drivers/gpu/drm/gma500/psb_drm.h line 73
Quoted 5 lines
drivers/gpu/drm/gma500/psb_drm.h new file +5
-0+ +struct drm_psb_stolen_memory_arg { + u32 base; + u32 size; +};Why does someone care about this? is it a workaround for lack of decent memory management?
A smart GMA500 aware server can allocate GEM objects from host memory or from the stolen memory area. Being smart about it really means knowing how much stolen memory is so it can see how best to use it.
Quoted 6 lines
Quoted 6 lines
drivers/gpu/drm/gma500/psb_drm.h new file +6
-0+/* Controlling the kernel modesetting buffers */ + +#define DRM_PSB_SIZES 0x07 +#define DRM_PSB_FUSE_REG 0x08 +#define DRM_PSB_DC_STATE 0x0A +#define DRM_PSB_ADB 0x0B
Quoted 8 lines
drivers/gpu/drm/gma500/psb_drm.h line 154
Quoted 3 lines
drivers/gpu/drm/gma500/psb_drm.h new file +3
-0+#define DRM_PSB_MODE_OPERATION 0x0C +#define DRM_PSB_STOLEN_MEMORY 0x0D +#define DRM_PSB_REGISTER_RW 0x0EDirect read/writing of registers is not something, the regs being hit here seem like workarounds for not having good overlay support in the kernel perhaps,
can the new plane stuff help workaround this?
That can go - its basically left for debugging.
Quoted 3 lines
So you can probably considered these patches merged at least, I'll just keep them in a topic branch which I'll stick into the drm-next queue.
Cool.
I'll take the secateurs to the interfaces.
_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
PATCH 9/12 gma500: Add Poulsbo support
In reply to Alan CoxFrom: Alan Cox <[email protected]>
This provides the specific code for Poulsbo, some of which is also used for the later chipsets. We support the GTT, the 2D engine (for console), and the display setup/management. We do not support 3D or the video overlays.
In theory enough public info is available to do the video overlay work but that represents a large task.
Framebuffer X will run nicely with this but do *NOT* use the VESA X server at the same time as KMS. With a Dell mini 10 things like Xfce4 are nice and usable even when compositing as the CPU has a good path to the memory.
---
drivers/gpu/drm/gma500/psb_device.c | 353 ++++++ drivers/gpu/drm/gma500/psb_gfx.mod.c | 51 + drivers/gpu/drm/gma500/psb_intel_display.c | 1431 ++++++++++++++++++++++++++ drivers/gpu/drm/gma500/psb_intel_display.h | 28 + drivers/gpu/drm/gma500/psb_intel_drv.h | 228 ++++ drivers/gpu/drm/gma500/psb_intel_lvds.c | 849 +++++++++++++++ drivers/gpu/drm/gma500/psb_intel_modes.c | 77 + drivers/gpu/drm/gma500/psb_intel_reg.h | 1235 ++++++++++++++++++++++ drivers/gpu/drm/gma500/psb_intel_sdvo.c | 1293 +++++++++++++++++++++++ drivers/gpu/drm/gma500/psb_intel_sdvo_regs.h | 338 ++++++ drivers/gpu/drm/gma500/psb_lid.c | 90 ++ 11 files changed, 5973 insertions(+), 0 deletions(-) create mode 100644 drivers/gpu/drm/gma500/psb_device.c create mode 100644 drivers/gpu/drm/gma500/psb_gfx.mod.c create mode 100644 drivers/gpu/drm/gma500/psb_intel_display.c create mode 100644 drivers/gpu/drm/gma500/psb_intel_display.h create mode 100644 drivers/gpu/drm/gma500/psb_intel_drv.h create mode 100644 drivers/gpu/drm/gma500/psb_intel_lvds.c create mode 100644 drivers/gpu/drm/gma500/psb_intel_modes.c create mode 100644 drivers/gpu/drm/gma500/psb_intel_reg.h create mode 100644 drivers/gpu/drm/gma500/psb_intel_sdvo.c create mode 100644 drivers/gpu/drm/gma500/psb_intel_sdvo_regs.h create mode 100644 drivers/gpu/drm/gma500/psb_lid.c
drivers/gpu/drm/gma500/psb_device.c new file +353 -0
@@ -0,0 +1,353 @@ +/************************************************************************** +* Copyright (c) 2011, Intel Corporation. +* All Rights Reserved. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation, Inc., +* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +* +**************************************************************************/ + +#include <linux/backlight.h> +#include <drm/drmP.h> +#include <drm/drm.h> +#include "psb_drm.h" +#include "psb_drv.h" +#include "psb_reg.h" +#include "psb_intel_reg.h" +#include "intel_bios.h" + + +static int psb_output_init (struct drm_device *dev) +{ +struct drm_psb_private *dev_priv = dev->dev_private; +psb_intel_lvds_init (dev, &dev_priv->mode_dev); +psb_intel_sdvo_init (dev,SDVOB ); +return 0 ; +} + +#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE + +/* +* Poulsbo Backlight Interfaces +*/ + +#define BLC_PWM_PRECISION_FACTOR 100/* 10000000 */ +#define BLC_PWM_FREQ_CALC_CONSTANT 32 +#define MHz 1000000 + +#define PSB_BLC_PWM_PRECISION_FACTOR 10 +#define PSB_BLC_MAX_PWM_REG_FREQ 0xFFFE +#define PSB_BLC_MIN_PWM_REG_FREQ 0x2 + +#define PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE) +#define PSB_BACKLIGHT_PWM_CTL_SHIFT (16) + +static int psb_brightness; +static struct backlight_device *psb_backlight_device; + +static int psb_get_brightness (struct backlight_device *bd) +{ +/* return locally cached var instead of HW read (due to DPST etc.) */ +/* FIXME: ideally return actual value in case firmware fiddled with +it */ +return psb_brightness; +} + + +static int psb_backlight_setup (struct drm_device *dev) +{ +struct drm_psb_private *dev_priv = dev->dev_private; +unsigned long core_clock; +/* u32 bl_max_freq; */ +/* unsigned long value; */ +u16 bl_max_freq; +uint32_t value; +uint32_t blc_pwm_precision_factor; + +/* get bl_max_freq and pol from dev_priv*/ +if (!dev_priv->lvds_bl) { +dev_err (dev->dev,"Has no valid LVDS backlight info\n" ); +return -ENOENT ; + } + bl_max_freq = dev_priv->lvds_bl->freq; + blc_pwm_precision_factor =PSB_BLC_PWM_PRECISION_FACTOR ; + + core_clock = dev_priv->core_freq; + + value = (core_clock * MHz) /BLC_PWM_FREQ_CALC_CONSTANT ; + value *= blc_pwm_precision_factor; + value /= bl_max_freq; + value /= blc_pwm_precision_factor; + +if (value > (unsigned long long )PSB_BLC_MAX_PWM_REG_FREQ || + value < (unsigned long long )PSB_BLC_MIN_PWM_REG_FREQ ) +return -ERANGE ; +else { + value &=PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR ; +REG_WRITE (BLC_PWM_CTL , + (value <<PSB_BACKLIGHT_PWM_CTL_SHIFT ) | (value)); + } +return 0 ; +} + +static int psb_set_brightness (struct backlight_device *bd) +{ +struct drm_device *dev =bl_get_data (psb_backlight_device); +int level = bd->props.brightness; + +/* Percentage 1-100% being valid */ +if (level <1 ) + level =1 ; + +psb_intel_lvds_set_brightness (dev, level); + psb_brightness = level; +return 0 ; +} + +static const struct backlight_ops psb_ops = { + .get_brightness = psb_get_brightness, + .update_status = psb_set_brightness, +}; + +static int psb_backlight_init (struct drm_device *dev) +{ +struct drm_psb_private *dev_priv = dev->dev_private; +int ret; +struct backlight_properties props; + +memset (&props,0 ,sizeof (struct backlight_properties )); + props.max_brightness =100 ; + props.type =BACKLIGHT_PLATFORM ; + + psb_backlight_device =backlight_device_register ("psb-bl" , +NULL , (void *)dev, &psb_ops, &props); +if (IS_ERR (psb_backlight_device)) +return PTR_ERR (psb_backlight_device); + + ret =psb_backlight_setup (dev); +if (ret <0 ) { +backlight_device_unregister (psb_backlight_device); + psb_backlight_device =NULL ; +return ret; + } + psb_backlight_device->props.brightness =100 ; + psb_backlight_device->props.max_brightness =100 ; +backlight_update_status (psb_backlight_device); + dev_priv->backlight_device = psb_backlight_device; +return 0 ; +} + +#endif + +/* +* Provide the Poulsbo specific chip logic and low level methods +* for power management +*/ + +static void psb_init_pm (struct drm_device *dev) +{ +struct drm_psb_private *dev_priv = dev->dev_private; + +u32 gating =PSB_RSGX32 (PSB_CR_CLKGATECTL ); + gating &= ~3 ;/* Disable 2D clock gating */ + gating |=1 ; +PSB_WSGX32 (gating,PSB_CR_CLKGATECTL ); +PSB_RSGX32 (PSB_CR_CLKGATECTL ); +} + +/** +* psb_save_display_registers - save registers lost on suspend +* @dev: our DRM device +* +* Save the state we need in order to be able to restore the interface +* upon resume from suspend +*/ +static int psb_save_display_registers (struct drm_device *dev) +{ +struct drm_psb_private *dev_priv = dev->dev_private; +struct drm_crtc *crtc; +struct drm_connector *connector; + +/* Display arbitration control + watermarks */ + dev_priv->saveDSPARB =PSB_RVDC32 (DSPARB ); + dev_priv->saveDSPFW1 =PSB_RVDC32 (DSPFW1 ); + dev_priv->saveDSPFW2 =PSB_RVDC32 (DSPFW2 ); + dev_priv->saveDSPFW3 =PSB_RVDC32 (DSPFW3 ); + dev_priv->saveDSPFW4 =PSB_RVDC32 (DSPFW4 ); + dev_priv->saveDSPFW5 =PSB_RVDC32 (DSPFW5 ); + dev_priv->saveDSPFW6 =PSB_RVDC32 (DSPFW6 ); + dev_priv->saveCHICKENBIT =PSB_RVDC32 (DSPCHICKENBIT ); + +/* Save crtc and output state */ +mutex_lock (&dev->mode_config.mutex); +list_for_each_entry (crtc, &dev->mode_config.crtc_list, head) { +if (drm_helper_crtc_in_use (crtc)) + crtc->funcs->save (crtc); + } + +list_for_each_entry (connector, &dev->mode_config.connector_list, head) + connector->funcs->save (connector); + +mutex_unlock (&dev->mode_config.mutex); +return 0 ; +} + +/** +* psb_restore_display_registers - restore lost register state +* @dev: our DRM device +* +* Restore register state that was lost during suspend and resume. +*/ +static int psb_restore_display_registers (struct drm_device *dev) +{ +struct drm_psb_private *dev_priv = dev->dev_private; +struct drm_crtc *crtc; +struct drm_connector *connector; +int pp_stat; + +/* Display arbitration + watermarks */ +PSB_WVDC32 (dev_priv->saveDSPARB,DSPARB ); +PSB_WVDC32 (dev_priv->saveDSPFW1,DSPFW1 ); +PSB_WVDC32 (dev_priv->saveDSPFW2,DSPFW2 ); +PSB_WVDC32 (dev_priv->saveDSPFW3,DSPFW3 ); +PSB_WVDC32 (dev_priv->saveDSPFW4,DSPFW4 ); +PSB_WVDC32 (dev_priv->saveDSPFW5,DSPFW5 ); +PSB_WVDC32 (dev_priv->saveDSPFW6,DSPFW6 ); +PSB_WVDC32 (dev_priv->saveCHICKENBIT,DSPCHICKENBIT ); + +/*make sure VGA plane is off. it initializes to on after reset!*/ +PSB_WVDC32 (0x80000000 ,VGACNTRL ); + +mutex_lock (&dev->mode_config.mutex); +list_for_each_entry (crtc, &dev->mode_config.crtc_list, head) +if (drm_helper_crtc_in_use (crtc)) + crtc->funcs->restore (crtc); + +list_for_each_entry (connector, &dev->mode_config.connector_list, head) + connector->funcs->restore (connector); + +mutex_unlock (&dev->mode_config.mutex); + +if (dev_priv->iLVDS_enable) { +/*shutdown the panel*/ +PSB_WVDC32 (0 ,PP_CONTROL ); +do { + pp_stat =PSB_RVDC32 (PP_STATUS ); + }while (pp_stat &0x80000000 ); + +/* Turn off the plane */ +PSB_WVDC32 (0x58000000 ,DSPACNTR ); +PSB_WVDC32 (0 ,DSPASURF );/*trigger the plane disable*/ +/* Wait ~4 ticks */ +msleep (4 ); +/* Turn off pipe */ +PSB_WVDC32 (0x0 ,PIPEACONF ); +/* Wait ~8 ticks */ +msleep (8 ); + +/* Turn off PLLs */ +PSB_WVDC32 (0 ,MRST_DPLL_A ); + }else { +PSB_WVDC32 (DPI_SHUT_DOWN ,DPI_CONTROL_REG ); +PSB_WVDC32 (0x0 ,PIPEACONF ); +PSB_WVDC32 (0x2faf0000 ,BLC_PWM_CTL ); +while (REG_READ (0x70008 ) &0x40000000 ) +cpu_relax (); +while ((PSB_RVDC32 (GEN_FIFO_STAT_REG ) &DPI_FIFO_EMPTY ) + !=DPI_FIFO_EMPTY ) +cpu_relax (); +PSB_WVDC32 (0 ,DEVICE_READY_REG ); + } +return 0 ; +} + +static int psb_power_down (struct drm_device *dev) +{ +return 0 ; +} + +static int psb_power_up (struct drm_device *dev) +{ +return 0 ; +} + +static void psb_get_core_freq (struct drm_device *dev) +{ +uint32_t clock; +struct pci_dev *pci_root =pci_get_bus_and_slot (0 ,0 ); +struct drm_psb_private *dev_priv = dev->dev_private; + +/*pci_write_config_dword(pci_root, 0xD4, 0x00C32004);*/ +/*pci_write_config_dword(pci_root, 0xD0, 0xE0033000);*/ + +pci_write_config_dword (pci_root,0xD0 ,0xD0050300 ); +pci_read_config_dword (pci_root,0xD4 , &clock); +pci_dev_put (pci_root); + +switch (clock &0x07 ) { +case 0 : + dev_priv->core_freq =100 ; +break ; +case 1 : + dev_priv->core_freq =133 ; +break ; +case 2 : + dev_priv->core_freq =150 ; +break ; +case 3 : + dev_priv->core_freq =178 ; +break ; +case 4 : + dev_priv->core_freq =200 ; +break ; +case 5 : +case 6 : +case 7 : + dev_priv->core_freq =266 ; +default : + dev_priv->core_freq =0 ; + } +} + +static int psb_chip_setup (struct drm_device *dev) +{ +psb_get_core_freq (dev); +gma_intel_opregion_init (dev); +psb_intel_init_bios (dev); +return 0 ; +} + +const struct psb_ops psb_chip_ops = { + .name ="Poulsbo" , + .accel_2d =1 , + .pipes =2 , + .crtcs =2 , + .sgx_offset =PSB_SGX_OFFSET , + .chip_setup = psb_chip_setup, + + .crtc_helper = &psb_intel_helper_funcs, + .crtc_funcs = &psb_intel_crtc_funcs, + + .output_init = psb_output_init, + +#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE + .backlight_init = psb_backlight_init, +#endif + + .init_pm = psb_init_pm, + .save_regs = psb_save_display_registers, + .restore_regs = psb_restore_display_registers, + .power_down = psb_power_down, + .power_up = psb_power_up, +}; +
drivers/gpu/drm/gma500/psb_gfx.mod.c new file +51 -0
51 lines not on this page · raw message
drivers/gpu/drm/gma500/psb_intel_display.c new file +1431 -0
1,431 lines not on this page · raw message
drivers/gpu/drm/gma500/psb_intel_display.h new file +28 -0
@@ -0,0 +1,28 @@ +/* copyright (c) 2008, Intel Corporation +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation, Inc., +* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +* +* Authors: +* Eric Anholt <[email protected]> +*/ + +#ifndef _INTEL_DISPLAY_H_ +#define _INTEL_DISPLAY_H_ + +bool psb_intel_pipe_has_type (struct drm_crtc *crtc,int type); +void psb_intel_crtc_gamma_set (struct drm_crtc *crtc,u16 *red, +u16 *green,u16 *blue,uint32_t type,uint32_t size); +void psb_intel_crtc_destroy (struct drm_crtc *crtc); + +#endif
drivers/gpu/drm/gma500/psb_intel_drv.h new file +228 -0
228 lines not on this page · raw message
drivers/gpu/drm/gma500/psb_intel_lvds.c new file +849 -0
849 lines not on this page · raw message
drivers/gpu/drm/gma500/psb_intel_modes.c new file +77 -0
60 lines not on this page · raw message
drivers/gpu/drm/gma500/psb_intel_reg.h new file +1235 -0
1,235 lines not on this page · raw message
drivers/gpu/drm/gma500/psb_intel_sdvo.c new file +1293 -0
1,293 lines not on this page · raw message
drivers/gpu/drm/gma500/psb_intel_sdvo_regs.h new file +338 -0
338 lines not on this page · raw message
drivers/gpu/drm/gma500/psb_lid.c new file +90 -0
90 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
Part of the diff is not shown here. View the raw message.
PATCH 10/12 gma500: Add Oaktrail support
In reply to Alan CoxFrom: Alan Cox <[email protected]>
Oaktrail (GMA600) is found on some tablet/slate PC type systems. It's a bit different to the GMA500 but similar enough it makes sense to plug it into the same driver.
---
drivers/gpu/drm/gma500/oaktrail.h | 252 ++++++++ drivers/gpu/drm/gma500/oaktrail_crtc.c | 610 ++++++++++++++++++++ drivers/gpu/drm/gma500/oaktrail_device.c | 489 ++++++++++++++++ drivers/gpu/drm/gma500/oaktrail_hdmi.c | 852 ++++++++++++++++++++++++++++ drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c | 327 +++++++++++ drivers/gpu/drm/gma500/oaktrail_lvds.c | 406 +++++++++++++ 6 files changed, 2936 insertions(+), 0 deletions(-) create mode 100644 drivers/gpu/drm/gma500/oaktrail.h create mode 100644 drivers/gpu/drm/gma500/oaktrail_crtc.c create mode 100644 drivers/gpu/drm/gma500/oaktrail_device.c create mode 100644 drivers/gpu/drm/gma500/oaktrail_hdmi.c create mode 100644 drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c create mode 100644 drivers/gpu/drm/gma500/oaktrail_lvds.c
drivers/gpu/drm/gma500/oaktrail.h new file +252 -0
@@ -0,0 +1,252 @@ +/************************************************************************** +* Copyright (c) 2007-2011, Intel Corporation. +* All Rights Reserved. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation, Inc., +* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +* +**************************************************************************/ + +/* MID device specific descriptors */ + +struct oaktrail_vbt { +s8 signature[4 ];/*4 bytes,"$GCT" */ +u8 revision; +u8 size; +u8 checksum; +void *oaktrail_gct; +} __packed; + +struct oaktrail_timing_info { +u16 pixel_clock; +u8 hactive_lo; +u8 hblank_lo; +u8 hblank_hi:4 ; +u8 hactive_hi:4 ; +u8 vactive_lo; +u8 vblank_lo; +u8 vblank_hi:4 ; +u8 vactive_hi:4 ; +u8 hsync_offset_lo; +u8 hsync_pulse_width_lo; +u8 vsync_pulse_width_lo:4 ; +u8 vsync_offset_lo:4 ; +u8 vsync_pulse_width_hi:2 ; +u8 vsync_offset_hi:2 ; +u8 hsync_pulse_width_hi:2 ; +u8 hsync_offset_hi:2 ; +u8 width_mm_lo; +u8 height_mm_lo; +u8 height_mm_hi:4 ; +u8 width_mm_hi:4 ; +u8 hborder; +u8 vborder; +u8 unknown0:1 ; +u8 hsync_positive:1 ; +u8 vsync_positive:1 ; +u8 separate_sync:2 ; +u8 stereo:1 ; +u8 unknown6:1 ; +u8 interlaced:1 ; +} __packed; + +struct gct_r10_timing_info { +u16 pixel_clock; +u32 hactive_lo:8 ; +u32 hactive_hi:4 ; +u32 hblank_lo:8 ; +u32 hblank_hi:4 ; +u32 hsync_offset_lo:8 ; +u16 hsync_offset_hi:2 ; +u16 hsync_pulse_width_lo:8 ; +u16 hsync_pulse_width_hi:2 ; +u16 hsync_positive:1 ; +u16 rsvd_1:3 ; +u8 vactive_lo:8 ; +u16 vactive_hi:4 ; +u16 vblank_lo:8 ; +u16 vblank_hi:4 ; +u16 vsync_offset_lo:4 ; +u16 vsync_offset_hi:2 ; +u16 vsync_pulse_width_lo:4 ; +u16 vsync_pulse_width_hi:2 ; +u16 vsync_positive:1 ; +u16 rsvd_2:3 ; +} __packed; + +struct oaktrail_panel_descriptor_v1 { +u32 Panel_Port_Control;/* 1 dword, Register 0x61180 if LVDS */ +/* 0x61190 if MIPI */ +u32 Panel_Power_On_Sequencing;/*1 dword,Register 0x61208,*/ +u32 Panel_Power_Off_Sequencing;/*1 dword,Register 0x6120C,*/ +u32 Panel_Power_Cycle_Delay_and_Reference_Divisor;/* 1 dword */ +/* Register 0x61210 */ +struct oaktrail_timing_info DTD;/*18 bytes, Standard definition */ +u16 Panel_Backlight_Inverter_Descriptor;/* 16 bits, as follows */ +/* Bit 0, Frequency, 15 bits,0 - 32767Hz */ +/* Bit 15, Polarity, 1 bit, 0: Normal, 1: Inverted */ +u16 Panel_MIPI_Display_Descriptor; +/*16 bits, Defined as follows: */ +/* if MIPI, 0x0000 if LVDS */ +/* Bit 0, Type, 2 bits, */ +/* 0: Type-1, */ +/* 1: Type-2, */ +/* 2: Type-3, */ +/* 3: Type-4 */ +/* Bit 2, Pixel Format, 4 bits */ +/* Bit0: 16bpp (not supported in LNC), */ +/* Bit1: 18bpp loosely packed, */ +/* Bit2: 18bpp packed, */ +/* Bit3: 24bpp */ +/* Bit 6, Reserved, 2 bits, 00b */ +/* Bit 8, Minimum Supported Frame Rate, 6 bits, 0 - 63Hz */ +/* Bit 14, Reserved, 2 bits, 00b */ +} __packed; + +struct oaktrail_panel_descriptor_v2 { +u32 Panel_Port_Control;/* 1 dword, Register 0x61180 if LVDS */ +/* 0x61190 if MIPI */ +u32 Panel_Power_On_Sequencing;/*1 dword,Register 0x61208,*/ +u32 Panel_Power_Off_Sequencing;/*1 dword,Register 0x6120C,*/ +u8 Panel_Power_Cycle_Delay_and_Reference_Divisor;/* 1 byte */ +/* Register 0x61210 */ +struct oaktrail_timing_info DTD;/*18 bytes, Standard definition */ +u16 Panel_Backlight_Inverter_Descriptor;/*16 bits, as follows*/ +/*Bit 0, Frequency, 16 bits, 0 - 32767Hz*/ +u8 Panel_Initial_Brightness;/* [7:0] 0 - 100% */ +/*Bit 7, Polarity, 1 bit,0: Normal, 1: Inverted*/ +u16 Panel_MIPI_Display_Descriptor; +/*16 bits, Defined as follows: */ +/* if MIPI, 0x0000 if LVDS */ +/* Bit 0, Type, 2 bits, */ +/* 0: Type-1, */ +/* 1: Type-2, */ +/* 2: Type-3, */ +/* 3: Type-4 */ +/* Bit 2, Pixel Format, 4 bits */ +/* Bit0: 16bpp (not supported in LNC), */ +/* Bit1: 18bpp loosely packed, */ +/* Bit2: 18bpp packed, */ +/* Bit3: 24bpp */ +/* Bit 6, Reserved, 2 bits, 00b */ +/* Bit 8, Minimum Supported Frame Rate, 6 bits, 0 - 63Hz */ +/* Bit 14, Reserved, 2 bits, 00b */ +} __packed; + +union oaktrail_panel_rx { +struct { +u16 NumberOfLanes:2 ;/*Num of Lanes, 2 bits,0 = 1 lane,*/ +/* 1 = 2 lanes, 2 = 3 lanes, 3 = 4 lanes. */ +u16 MaxLaneFreq:3 ;/* 0: 100MHz, 1: 200MHz, 2: 300MHz, */ +/*3: 400MHz, 4: 500MHz, 5: 600MHz, 6: 700MHz, 7: 800MHz.*/ +u16 SupportedVideoTransferMode:2 ;/*0: Non-burst only */ +/* 1: Burst and non-burst */ +/* 2/3: Reserved */ +u16 HSClkBehavior:1 ;/*0: Continuous, 1: Non-continuous*/ +u16 DuoDisplaySupport:1 ;/*1 bit,0: No, 1: Yes*/ +u16 ECC_ChecksumCapabilities:1 ;/*1 bit,0: No, 1: Yes*/ +u16 BidirectionalCommunication:1 ;/*1 bit,0: No, 1: Yes */ +u16 Rsvd:5 ;/*5 bits,00000b */ + } panelrx; +u16 panel_receiver; +} __packed; + +struct oaktrail_gct_v1 { +union {/*8 bits,Defined as follows: */ +struct { +u8 PanelType:4 ;/*4 bits, Bit field for panels*/ +/* 0 - 3: 0 = LVDS, 1 = MIPI*/ +/*2 bits,Specifies which of the*/ +u8 BootPanelIndex:2 ; +/* 4 panels to use by default*/ +u8 BootMIPI_DSI_RxIndex:2 ;/*Specifies which of*/ +/* the 4 MIPI DSI receivers to use*/ + } PD; +u8 PanelDescriptor; + }; +struct oaktrail_panel_descriptor_v1 panel[4 ];/*panel descrs,38 bytes each*/ +union oaktrail_panel_rx panelrx[4 ];/* panel receivers*/ +} __packed; + +struct oaktrail_gct_v2 { +union {/*8 bits,Defined as follows: */ +struct { +u8 PanelType:4 ;/*4 bits, Bit field for panels*/ +/* 0 - 3: 0 = LVDS, 1 = MIPI*/ +/*2 bits,Specifies which of the*/ +u8 BootPanelIndex:2 ; +/* 4 panels to use by default*/ +u8 BootMIPI_DSI_RxIndex:2 ;/*Specifies which of*/ +/* the 4 MIPI DSI receivers to use*/ + } PD; +u8 PanelDescriptor; + }; +struct oaktrail_panel_descriptor_v2 panel[4 ];/*panel descrs,38 bytes each*/ +union oaktrail_panel_rx panelrx[4 ];/* panel receivers*/ +} __packed; + +struct oaktrail_gct_data { +u8 bpi;/* boot panel index, number of panel used during boot */ +u8 pt;/* panel type, 4 bit field, 0=lvds, 1=mipi */ +struct oaktrail_timing_info DTD;/* timing info for the selected panel */ +u32 Panel_Port_Control; +u32 PP_On_Sequencing;/*1 dword,Register 0x61208,*/ +u32 PP_Off_Sequencing;/*1 dword,Register 0x6120C,*/ +u32 PP_Cycle_Delay; +u16 Panel_Backlight_Inverter_Descriptor; +u16 Panel_MIPI_Display_Descriptor; +} __packed; + +#define MODE_SETTING_IN_CRTC 0x1 +#define MODE_SETTING_IN_ENCODER 0x2 +#define MODE_SETTING_ON_GOING 0x3 +#define MODE_SETTING_IN_DSR 0x4 +#define MODE_SETTING_ENCODER_DONE 0x8 + +#define GCT_R10_HEADER_SIZE 16 +#define GCT_R10_DISPLAY_DESC_SIZE 28 + +/* +* Moorestown HDMI interfaces +*/ + +struct oaktrail_hdmi_dev { +struct pci_dev *dev; +void __iomem *regs; +unsigned int mmio, mmio_len; +int dpms_mode; +struct hdmi_i2c_dev *i2c_dev; + +/* register state */ +u32 saveDPLL_CTRL; +u32 saveDPLL_DIV_CTRL; +u32 saveDPLL_ADJUST; +u32 saveDPLL_UPDATE; +u32 saveDPLL_CLK_ENABLE; +u32 savePCH_HTOTAL_B; +u32 savePCH_HBLANK_B; +u32 savePCH_HSYNC_B; +u32 savePCH_VTOTAL_B; +u32 savePCH_VBLANK_B; +u32 savePCH_VSYNC_B; +u32 savePCH_PIPEBCONF; +u32 savePCH_PIPEBSRC; +}; + +extern void oaktrail_hdmi_setup (struct drm_device *dev); +extern void oaktrail_hdmi_teardown (struct drm_device *dev); +extern int oaktrail_hdmi_i2c_init (struct pci_dev *dev); +extern void oaktrail_hdmi_i2c_exit (struct pci_dev *dev); +extern void oaktrail_hdmi_save (struct drm_device *dev); +extern void oaktrail_hdmi_restore (struct drm_device *dev); +extern void oaktrail_hdmi_init (struct drm_device *dev,struct psb_intel_mode_device *mode_dev);
drivers/gpu/drm/gma500/oaktrail_crtc.c new file +610 -0
610 lines not on this page · raw message
drivers/gpu/drm/gma500/oaktrail_device.c new file +489 -0
489 lines not on this page · raw message
drivers/gpu/drm/gma500/oaktrail_hdmi.c new file +852 -0
852 lines not on this page · raw message
drivers/gpu/drm/gma500/oaktrail_hdmi_i2c.c new file +327 -0
327 lines not on this page · raw message
drivers/gpu/drm/gma500/oaktrail_lvds.c new file +406 -0
406 lines not on this page · raw message
_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
PATCH 11/12 gma500: Add support for Cedarview
In reply to Alan CoxFrom: Alan Cox <[email protected]>
Again this is similar but has some differences so we have a set of plug in support. This does make the driver bigger than is needed in some respects but the tradeoff for maintainability is huge.
---
drivers/gpu/drm/gma500/cdv_device.c | 351 +++++++ drivers/gpu/drm/gma500/cdv_device.h | 36 + drivers/gpu/drm/gma500/cdv_intel_crt.c | 326 ++++++ drivers/gpu/drm/gma500/cdv_intel_display.c | 1508 ++++++++++++++++++++++++++++ drivers/gpu/drm/gma500/cdv_intel_hdmi.c | 376 +++++++ drivers/gpu/drm/gma500/cdv_intel_lvds.c | 721 +++++++++++++ 6 files changed, 3318 insertions(+), 0 deletions(-) create mode 100644 drivers/gpu/drm/gma500/cdv_device.c create mode 100644 drivers/gpu/drm/gma500/cdv_device.h create mode 100644 drivers/gpu/drm/gma500/cdv_intel_crt.c create mode 100644 drivers/gpu/drm/gma500/cdv_intel_display.c create mode 100644 drivers/gpu/drm/gma500/cdv_intel_hdmi.c create mode 100644 drivers/gpu/drm/gma500/cdv_intel_lvds.c
drivers/gpu/drm/gma500/cdv_device.c new file +351 -0
@@ -0,0 +1,351 @@ +/************************************************************************** +* Copyright (c) 2011, Intel Corporation. +* All Rights Reserved. +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation, Inc., +* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +* +**************************************************************************/ + +#include <linux/backlight.h> +#include <drm/drmP.h> +#include <drm/drm.h> +#include "psb_drm.h" +#include "psb_drv.h" +#include "psb_reg.h" +#include "psb_intel_reg.h" +#include "intel_bios.h" +#include "cdv_device.h" + +#define VGA_SR_INDEX 0x3c4 +#define VGA_SR_DATA 0x3c5 + +/* FIXME: should check if we are the active VGA device ?? */ +static void cdv_disable_vga (struct drm_device *dev) +{ +u8 sr1; +u32 vga_reg; + + vga_reg =VGACNTRL ; + +outb (1 ,VGA_SR_INDEX ); + sr1 =inb (VGA_SR_DATA ); +outb (sr1 |1 <<5 ,VGA_SR_DATA ); +udelay (300 ); + +REG_WRITE (vga_reg,VGA_DISP_DISABLE ); +REG_READ (vga_reg); +} + +static int cdv_output_init (struct drm_device *dev) +{ +struct drm_psb_private *dev_priv = dev->dev_private; +cdv_disable_vga (dev); + +cdv_intel_crt_init (dev, &dev_priv->mode_dev); +cdv_intel_lvds_init (dev, &dev_priv->mode_dev); + +/* These bits indicate HDMI not SDVO on CDV, but we don't yet support +the HDMI interface */ +if (REG_READ (SDVOB ) &SDVO_DETECTED ) +cdv_hdmi_init (dev, &dev_priv->mode_dev,SDVOB ); +if (REG_READ (SDVOC ) &SDVO_DETECTED ) +cdv_hdmi_init (dev, &dev_priv->mode_dev,SDVOC ); +return 0 ; +} + +#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE + +/* +* Poulsbo Backlight Interfaces +*/ + +#define BLC_PWM_PRECISION_FACTOR 100/* 10000000 */ +#define BLC_PWM_FREQ_CALC_CONSTANT 32 +#define MHz 1000000 + +#define PSB_BLC_PWM_PRECISION_FACTOR 10 +#define PSB_BLC_MAX_PWM_REG_FREQ 0xFFFE +#define PSB_BLC_MIN_PWM_REG_FREQ 0x2 + +#define PSB_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE) +#define PSB_BACKLIGHT_PWM_CTL_SHIFT (16) + +static int cdv_brightness; +static struct backlight_device *cdv_backlight_device; + +static int cdv_get_brightness (struct backlight_device *bd) +{ +/* return locally cached var instead of HW read (due to DPST etc.) */ +/* FIXME: ideally return actual value in case firmware fiddled with +it */ +return cdv_brightness; +} + + +static int cdv_backlight_setup (struct drm_device *dev) +{ +struct drm_psb_private *dev_priv = dev->dev_private; +unsigned long core_clock; +/* u32 bl_max_freq; */ +/* unsigned long value; */ +u16 bl_max_freq; +uint32_t value; +uint32_t blc_pwm_precision_factor; + +/* get bl_max_freq and pol from dev_priv*/ +if (!dev_priv->lvds_bl) { +dev_err (dev->dev,"Has no valid LVDS backlight info\n" ); +return -ENOENT ; + } + bl_max_freq = dev_priv->lvds_bl->freq; + blc_pwm_precision_factor =PSB_BLC_PWM_PRECISION_FACTOR ; + + core_clock = dev_priv->core_freq; + + value = (core_clock * MHz) /BLC_PWM_FREQ_CALC_CONSTANT ; + value *= blc_pwm_precision_factor; + value /= bl_max_freq; + value /= blc_pwm_precision_factor; + +if (value > (unsigned long long )PSB_BLC_MAX_PWM_REG_FREQ || + value < (unsigned long long )PSB_BLC_MIN_PWM_REG_FREQ ) +return -ERANGE ; +else { +/* FIXME */ + } +return 0 ; +} + +static int cdv_set_brightness (struct backlight_device *bd) +{ +int level = bd->props.brightness; + +/* Percentage 1-100% being valid */ +if (level <1 ) + level =1 ; + +/*cdv_intel_lvds_set_brightness(dev, level); FIXME */ + cdv_brightness = level; +return 0 ; +} + +static const struct backlight_ops cdv_ops = { + .get_brightness = cdv_get_brightness, + .update_status = cdv_set_brightness, +}; + +static int cdv_backlight_init (struct drm_device *dev) +{ +struct drm_psb_private *dev_priv = dev->dev_private; +int ret; +struct backlight_properties props; + +memset (&props,0 ,sizeof (struct backlight_properties )); + props.max_brightness =100 ; + props.type =BACKLIGHT_PLATFORM ; + + cdv_backlight_device =backlight_device_register ("psb-bl" , +NULL , (void *)dev, &cdv_ops, &props); +if (IS_ERR (cdv_backlight_device)) +return PTR_ERR (cdv_backlight_device); + + ret =cdv_backlight_setup (dev); +if (ret <0 ) { +backlight_device_unregister (cdv_backlight_device); + cdv_backlight_device =NULL ; +return ret; + } + cdv_backlight_device->props.brightness =100 ; + cdv_backlight_device->props.max_brightness =100 ; +backlight_update_status (cdv_backlight_device); + dev_priv->backlight_device = cdv_backlight_device; +return 0 ; +} + +#endif + +/* +* Provide the Cedarview specific chip logic and low level methods +* for power management +* +* FIXME: we need to implement the apm/ospm base management bits +* for this and the MID devices. +*/ + +static inline u32 CDV_MSG_READ32 (uint port,uint offset) +{ +int mcr = (0x10 <<24 ) | (port <<16 ) | (offset <<8 ); +uint32_t ret_val =0 ; +struct pci_dev *pci_root =pci_get_bus_and_slot (0 ,0 ); +pci_write_config_dword (pci_root,0xD0 , mcr); +pci_read_config_dword (pci_root,0xD4 , &ret_val); +pci_dev_put (pci_root); +return ret_val; +} + +static inline void CDV_MSG_WRITE32 (uint port,uint offset,u32 value) +{ +int mcr = (0x11 <<24 ) | (port <<16 ) | (offset <<8 ) |0xF0 ; +struct pci_dev *pci_root =pci_get_bus_and_slot (0 ,0 ); +pci_write_config_dword (pci_root,0xD4 , value); +pci_write_config_dword (pci_root,0xD0 , mcr); +pci_dev_put (pci_root); +} + +#define PSB_APM_CMD 0x0 +#define PSB_APM_STS 0x04 +#define PSB_PM_SSC 0x20 +#define PSB_PM_SSS 0x30 +#define PSB_PWRGT_GFX_MASK 0x3 +#define CDV_PWRGT_DISPLAY_CNTR 0x000fc00c +#define CDV_PWRGT_DISPLAY_STS 0x000fc00c + +static void cdv_init_pm (struct drm_device *dev) +{ +struct drm_psb_private *dev_priv = dev->dev_private; +u32 pwr_cnt; +int i; + + dev_priv->apm_base =CDV_MSG_READ32 (PSB_PUNIT_PORT , +PSB_APMBA ) &0xFFFF ; + dev_priv->ospm_base =CDV_MSG_READ32 (PSB_PUNIT_PORT , +PSB_OSPMBA ) &0xFFFF ; + +/* Force power on for now */ + pwr_cnt =inl (dev_priv->apm_base +PSB_APM_CMD ); + pwr_cnt &= ~PSB_PWRGT_GFX_MASK ; + +outl (pwr_cnt, dev_priv->apm_base +PSB_APM_CMD ); +for (i =0 ; i <5 ; i++) { +u32 pwr_sts =inl (dev_priv->apm_base +PSB_APM_STS ); +if ((pwr_sts &PSB_PWRGT_GFX_MASK ) ==0 ) +break ; +udelay (10 ); + } + pwr_cnt =inl (dev_priv->ospm_base +PSB_PM_SSC ); + pwr_cnt &= ~CDV_PWRGT_DISPLAY_CNTR ; +outl (pwr_cnt, dev_priv->ospm_base +PSB_PM_SSC ); +for (i =0 ; i <5 ; i++) { +u32 pwr_sts =inl (dev_priv->ospm_base +PSB_PM_SSS ); +if ((pwr_sts &CDV_PWRGT_DISPLAY_STS ) ==0 ) +break ; +udelay (10 ); + } +} + +/** +* cdv_save_display_registers - save registers lost on suspend +* @dev: our DRM device +* +* Save the state we need in order to be able to restore the interface +* upon resume from suspend +* +* FIXME: review +*/ +static int cdv_save_display_registers (struct drm_device *dev) +{ +return 0 ; +} + +/** +* cdv_restore_display_registers - restore lost register state +* @dev: our DRM device +* +* Restore register state that was lost during suspend and resume. +* +* FIXME: review +*/ +static int cdv_restore_display_registers (struct drm_device *dev) +{ +return 0 ; +} + +static int cdv_power_down (struct drm_device *dev) +{ +return 0 ; +} + +static int cdv_power_up (struct drm_device *dev) +{ +return 0 ; +} + +/* FIXME ? - shared with Poulsbo */ +static void cdv_get_core_freq (struct drm_device *dev) +{ +uint32_t clock; +struct pci_dev *pci_root =pci_get_bus_and_slot (0 ,0 ); +struct drm_psb_private *dev_priv = dev->dev_private; + +pci_write_config_dword (pci_root,0xD0 ,0xD0050300 ); +pci_read_config_dword (pci_root,0xD4 , &clock); +pci_dev_put (pci_root); + +switch (clock &0x07 ) { +case 0 : + dev_priv->core_freq =100 ; +break ; +case 1 : + dev_priv->core_freq =133 ; +break ; +case 2 : + dev_priv->core_freq =150 ; +break ; +case 3 : + dev_priv->core_freq =178 ; +break ; +case 4 : + dev_priv->core_freq =200 ; +break ; +case 5 : +case 6 : +case 7 : + dev_priv->core_freq =266 ; +default : + dev_priv->core_freq =0 ; + } +} + +static int cdv_chip_setup (struct drm_device *dev) +{ +cdv_get_core_freq (dev); +gma_intel_opregion_init (dev); +psb_intel_init_bios (dev); +return 0 ; +} + +/* CDV is much like Poulsbo but has MID like SGX offsets and PM */ + +const struct psb_ops cdv_chip_ops = { + .name ="Cedartrail" , + .accel_2d =0 , + .pipes =2 , + .sgx_offset =MRST_SGX_OFFSET , + .chip_setup = cdv_chip_setup, + + .crtc_helper = &cdv_intel_helper_funcs, + .crtc_funcs = &cdv_intel_crtc_funcs, + + .output_init = cdv_output_init, + +#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE + .backlight_init = cdv_backlight_init, +#endif + + .init_pm = cdv_init_pm, + .save_regs = cdv_save_display_registers, + .restore_regs = cdv_restore_display_registers, + .power_down = cdv_power_down, + .power_up = cdv_power_up, +};
drivers/gpu/drm/gma500/cdv_device.h new file +36 -0
@@ -0,0 +1,36 @@ +/* +* Copyright © 2011 Intel Corporation +* +* This program is free software; you can redistribute it and/or modify it +* under the terms and conditions of the GNU General Public License, +* version 2, as published by the Free Software Foundation. +* +* This program is distributed in the hope 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 program; if not, write to the Free Software Foundation, Inc., +* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +extern const struct drm_crtc_helper_funcs cdv_intel_helper_funcs; +extern const struct drm_crtc_funcs cdv_intel_crtc_funcs; +extern void cdv_intel_crt_init (struct drm_device *dev, +struct psb_intel_mode_device *mode_dev); +extern void cdv_intel_lvds_init (struct drm_device *dev, +struct psb_intel_mode_device *mode_dev); +extern void cdv_hdmi_init (struct drm_device *dev,struct psb_intel_mode_device *mode_dev, +int reg); +extern struct drm_display_mode *cdv_intel_crtc_mode_get (struct drm_device *dev, +struct drm_crtc *crtc); + +extern inline void cdv_intel_wait_for_vblank (struct drm_device *dev) +{ +/* Wait for 20ms, i.e. one cycle at 50hz. */ +/* FIXME: msleep ?? */ +mdelay (20 ); +} + +
drivers/gpu/drm/gma500/cdv_intel_crt.c new file +326 -0
326 lines not on this page · raw message
drivers/gpu/drm/gma500/cdv_intel_display.c new file +1508 -0
1,508 lines not on this page · raw message
drivers/gpu/drm/gma500/cdv_intel_hdmi.c new file +376 -0
376 lines not on this page · raw message
drivers/gpu/drm/gma500/cdv_intel_lvds.c new file +721 -0
403 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel
Part of the diff is not shown here. View the raw message.
PATCH 12/12 gma500: Now connect up to the DRM build to finish the job
In reply to Alan CoxFrom: Alan Cox <[email protected]>
---
drivers/gpu/drm/Kconfig | 3 +++ drivers/gpu/drm/Makefile | 1 + 2 files changed, 4 insertions(+), 0 deletions(-)
drivers/gpu/drm/Kconfig +3 -0
@@ -158,3 +158,6 @@ config DRM_SAVAGE help Choose this option if you have a Savage3D/4/SuperSavage/Pro/Twister chipset. If M is selected the module will be called savage. + +source "drivers/gpu/drm/gma500/Kconfig" +
drivers/gpu/drm/Makefile +1 -0
@@ -35,4 +35,5 @@ obj-$(CONFIG_DRM_SAVAGE)+= savage/ obj-$(CONFIG_DRM_VMWGFX)+= vmwgfx/ obj-$(CONFIG_DRM_VIA) +=via/ obj-$(CONFIG_DRM_NOUVEAU) +=nouveau/ +obj-$(CONFIG_DRM_GMA500) += gma500/ obj-y += i2c/
Quoted 5 lines · Alan Cox
From: Alan Cox<[email protected]>
This driver supports unaccelerated KMS display, and accelerated console handling on the Intel Poulsbo, Oaktrail, Cedarview and Medfield hardware.
Quoted 9 lines
For the initial merge Medfield will be left out as it needs considerable further work to reach a decent standard
Begin by adding the Makefiles and
Kconfig. These are not yet plumbed into the DRM layer so will have no effect on their ownSigned-off-by Alan Cox<[email protected]>---
Alan,
Good to see some of this old code being used.
I haven't followed this work closely, but I have a question:
The first poulsbos used to crash badly when attempting to map the GTT write-combined, and IIRC it didn't even advertise write-combining capabilities on the PCI BAR. Has this been improved on lately or how is this handled currently?
Thanks,
Thomas
Quoted 4 lines
The first poulsbos used to crash badly when attempting to map the GTT write-combined, and IIRC it didn't even advertise write-combining capabilities on the PCI BAR. Has this been improved on lately or how is this handled currently?
It seems to be reliable in the current driver. Whether that is because I don't use the 3D engine and that causes problems I don't know. One thing longer term I want to poke at is cachability stuff to see if we can tune it a bit.