You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'drm-core-next' of git://people.freedesktop.org/~airlied/linux
* 'drm-core-next' of git://people.freedesktop.org/~airlied/linux: (290 commits) Revert "drm/ttm: add a way to bo_wait for either the last read or last write" Revert "drm/radeon/kms: add a new gem_wait ioctl with read/write flags" vmwgfx: Don't pass unused arguments to do_dirty functions vmwgfx: Emulate depth 32 framebuffers drm/radeon: Lower the severity of the radeon lockup messages. drm/i915/dp: Fix eDP on PCH DP on CPT/PPT drm/i915/dp: Introduce is_cpu_edp() drm/i915: use correct SPD type value drm/i915: fix ILK+ infoframe support drm/i915: add DP test request handling drm/i915: read full receiver capability field during DP hot plug drm/i915/dp: Remove eDP special cases from bandwidth checks drm/i915/dp: Fix the math in intel_dp_link_required drm/i915/panel: Always record the backlight level again (but cleverly) i915: Move i915_read/write out of line drm/i915: remove transcoder PLL mashing from mode_set per specs drm/i915: if transcoder disable fails, say which drm/i915: set watermarks for third pipe on IVB drm/i915: export a CPT mode set verification function drm/i915: fix transcoder PLL select masking ...
This commit is contained in:
@@ -923,6 +923,9 @@ static int intel_fake_agp_insert_entries(struct agp_memory *mem,
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (intel_private.base.do_idle_maps)
|
||||
return -ENODEV;
|
||||
|
||||
if (intel_private.clear_fake_agp) {
|
||||
int start = intel_private.base.stolen_size / PAGE_SIZE;
|
||||
int end = intel_private.base.gtt_mappable_entries;
|
||||
@@ -985,6 +988,9 @@ static int intel_fake_agp_remove_entries(struct agp_memory *mem,
|
||||
if (mem->page_count == 0)
|
||||
return 0;
|
||||
|
||||
if (intel_private.base.do_idle_maps)
|
||||
return -ENODEV;
|
||||
|
||||
intel_gtt_clear_range(pg_start, mem->page_count);
|
||||
|
||||
if (intel_private.base.needs_dmar) {
|
||||
@@ -1177,6 +1183,25 @@ static void gen6_cleanup(void)
|
||||
{
|
||||
}
|
||||
|
||||
/* Certain Gen5 chipsets require require idling the GPU before
|
||||
* unmapping anything from the GTT when VT-d is enabled.
|
||||
*/
|
||||
extern int intel_iommu_gfx_mapped;
|
||||
static inline int needs_idle_maps(void)
|
||||
{
|
||||
const unsigned short gpu_devid = intel_private.pcidev->device;
|
||||
|
||||
/* Query intel_iommu to see if we need the workaround. Presumably that
|
||||
* was loaded first.
|
||||
*/
|
||||
if ((gpu_devid == PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB ||
|
||||
gpu_devid == PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG) &&
|
||||
intel_iommu_gfx_mapped)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i9xx_setup(void)
|
||||
{
|
||||
u32 reg_addr;
|
||||
@@ -1211,6 +1236,9 @@ static int i9xx_setup(void)
|
||||
intel_private.gtt_bus_addr = reg_addr + gtt_offset;
|
||||
}
|
||||
|
||||
if (needs_idle_maps());
|
||||
intel_private.base.do_idle_maps = 1;
|
||||
|
||||
intel_i9xx_setup_flush();
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -158,3 +158,7 @@ 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/exynos/Kconfig"
|
||||
|
||||
source "drivers/gpu/drm/vmwgfx/Kconfig"
|
||||
|
||||
@@ -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_EXYNOS) +=exynos/
|
||||
obj-y += i2c/
|
||||
|
||||
@@ -372,11 +372,13 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
|
||||
encoder_funcs = encoder->helper_private;
|
||||
if (!(ret = encoder_funcs->mode_fixup(encoder, mode,
|
||||
adjusted_mode))) {
|
||||
DRM_DEBUG_KMS("Encoder fixup failed\n");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(ret = crtc_funcs->mode_fixup(crtc, mode, adjusted_mode))) {
|
||||
DRM_DEBUG_KMS("CRTC fixup failed\n");
|
||||
goto done;
|
||||
}
|
||||
DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
|
||||
|
||||
@@ -107,11 +107,8 @@ int drm_debugfs_create_files(struct drm_info_list *files, int count,
|
||||
ent = debugfs_create_file(files[i].name, S_IFREG | S_IRUGO,
|
||||
root, tmp, &drm_debugfs_fops);
|
||||
if (!ent) {
|
||||
char name[64];
|
||||
strncpy(name, root->d_name.name,
|
||||
min(root->d_name.len, 64U));
|
||||
DRM_ERROR("Cannot create /sys/kernel/debug/dri/%s/%s\n",
|
||||
name, files[i].name);
|
||||
root->d_name.name, files[i].name);
|
||||
kfree(tmp);
|
||||
ret = -1;
|
||||
goto fail;
|
||||
|
||||
@@ -438,6 +438,8 @@ long drm_ioctl(struct file *filp,
|
||||
goto err_i1;
|
||||
}
|
||||
}
|
||||
if (asize > usize)
|
||||
memset(kdata + usize, 0, asize - usize);
|
||||
}
|
||||
|
||||
if (cmd & IOC_IN) {
|
||||
|
||||
@@ -1319,6 +1319,7 @@ add_detailed_modes(struct drm_connector *connector, struct edid *edid,
|
||||
#define HDMI_IDENTIFIER 0x000C03
|
||||
#define AUDIO_BLOCK 0x01
|
||||
#define VENDOR_BLOCK 0x03
|
||||
#define SPEAKER_BLOCK 0x04
|
||||
#define EDID_BASIC_AUDIO (1 << 6)
|
||||
|
||||
/**
|
||||
@@ -1347,6 +1348,176 @@ u8 *drm_find_cea_extension(struct edid *edid)
|
||||
}
|
||||
EXPORT_SYMBOL(drm_find_cea_extension);
|
||||
|
||||
static void
|
||||
parse_hdmi_vsdb(struct drm_connector *connector, uint8_t *db)
|
||||
{
|
||||
connector->eld[5] |= (db[6] >> 7) << 1; /* Supports_AI */
|
||||
|
||||
connector->dvi_dual = db[6] & 1;
|
||||
connector->max_tmds_clock = db[7] * 5;
|
||||
|
||||
connector->latency_present[0] = db[8] >> 7;
|
||||
connector->latency_present[1] = (db[8] >> 6) & 1;
|
||||
connector->video_latency[0] = db[9];
|
||||
connector->audio_latency[0] = db[10];
|
||||
connector->video_latency[1] = db[11];
|
||||
connector->audio_latency[1] = db[12];
|
||||
|
||||
DRM_LOG_KMS("HDMI: DVI dual %d, "
|
||||
"max TMDS clock %d, "
|
||||
"latency present %d %d, "
|
||||
"video latency %d %d, "
|
||||
"audio latency %d %d\n",
|
||||
connector->dvi_dual,
|
||||
connector->max_tmds_clock,
|
||||
(int) connector->latency_present[0],
|
||||
(int) connector->latency_present[1],
|
||||
connector->video_latency[0],
|
||||
connector->video_latency[1],
|
||||
connector->audio_latency[0],
|
||||
connector->audio_latency[1]);
|
||||
}
|
||||
|
||||
static void
|
||||
monitor_name(struct detailed_timing *t, void *data)
|
||||
{
|
||||
if (t->data.other_data.type == EDID_DETAIL_MONITOR_NAME)
|
||||
*(u8 **)data = t->data.other_data.data.str.str;
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_edid_to_eld - build ELD from EDID
|
||||
* @connector: connector corresponding to the HDMI/DP sink
|
||||
* @edid: EDID to parse
|
||||
*
|
||||
* Fill the ELD (EDID-Like Data) buffer for passing to the audio driver.
|
||||
* Some ELD fields are left to the graphics driver caller:
|
||||
* - Conn_Type
|
||||
* - HDCP
|
||||
* - Port_ID
|
||||
*/
|
||||
void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid)
|
||||
{
|
||||
uint8_t *eld = connector->eld;
|
||||
u8 *cea;
|
||||
u8 *name;
|
||||
u8 *db;
|
||||
int sad_count = 0;
|
||||
int mnl;
|
||||
int dbl;
|
||||
|
||||
memset(eld, 0, sizeof(connector->eld));
|
||||
|
||||
cea = drm_find_cea_extension(edid);
|
||||
if (!cea) {
|
||||
DRM_DEBUG_KMS("ELD: no CEA Extension found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
name = NULL;
|
||||
drm_for_each_detailed_block((u8 *)edid, monitor_name, &name);
|
||||
for (mnl = 0; name && mnl < 13; mnl++) {
|
||||
if (name[mnl] == 0x0a)
|
||||
break;
|
||||
eld[20 + mnl] = name[mnl];
|
||||
}
|
||||
eld[4] = (cea[1] << 5) | mnl;
|
||||
DRM_DEBUG_KMS("ELD monitor %s\n", eld + 20);
|
||||
|
||||
eld[0] = 2 << 3; /* ELD version: 2 */
|
||||
|
||||
eld[16] = edid->mfg_id[0];
|
||||
eld[17] = edid->mfg_id[1];
|
||||
eld[18] = edid->prod_code[0];
|
||||
eld[19] = edid->prod_code[1];
|
||||
|
||||
for (db = cea + 4; db < cea + cea[2]; db += dbl + 1) {
|
||||
dbl = db[0] & 0x1f;
|
||||
|
||||
switch ((db[0] & 0xe0) >> 5) {
|
||||
case AUDIO_BLOCK: /* Audio Data Block, contains SADs */
|
||||
sad_count = dbl / 3;
|
||||
memcpy(eld + 20 + mnl, &db[1], dbl);
|
||||
break;
|
||||
case SPEAKER_BLOCK: /* Speaker Allocation Data Block */
|
||||
eld[7] = db[1];
|
||||
break;
|
||||
case VENDOR_BLOCK:
|
||||
/* HDMI Vendor-Specific Data Block */
|
||||
if (db[1] == 0x03 && db[2] == 0x0c && db[3] == 0)
|
||||
parse_hdmi_vsdb(connector, db);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
eld[5] |= sad_count << 4;
|
||||
eld[2] = (20 + mnl + sad_count * 3 + 3) / 4;
|
||||
|
||||
DRM_DEBUG_KMS("ELD size %d, SAD count %d\n", (int)eld[2], sad_count);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_edid_to_eld);
|
||||
|
||||
/**
|
||||
* drm_av_sync_delay - HDMI/DP sink audio-video sync delay in millisecond
|
||||
* @connector: connector associated with the HDMI/DP sink
|
||||
* @mode: the display mode
|
||||
*/
|
||||
int drm_av_sync_delay(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
int i = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
|
||||
int a, v;
|
||||
|
||||
if (!connector->latency_present[0])
|
||||
return 0;
|
||||
if (!connector->latency_present[1])
|
||||
i = 0;
|
||||
|
||||
a = connector->audio_latency[i];
|
||||
v = connector->video_latency[i];
|
||||
|
||||
/*
|
||||
* HDMI/DP sink doesn't support audio or video?
|
||||
*/
|
||||
if (a == 255 || v == 255)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Convert raw EDID values to millisecond.
|
||||
* Treat unknown latency as 0ms.
|
||||
*/
|
||||
if (a)
|
||||
a = min(2 * (a - 1), 500);
|
||||
if (v)
|
||||
v = min(2 * (v - 1), 500);
|
||||
|
||||
return max(v - a, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_av_sync_delay);
|
||||
|
||||
/**
|
||||
* drm_select_eld - select one ELD from multiple HDMI/DP sinks
|
||||
* @encoder: the encoder just changed display mode
|
||||
* @mode: the adjusted display mode
|
||||
*
|
||||
* It's possible for one encoder to be associated with multiple HDMI/DP sinks.
|
||||
* The policy is now hard coded to simply use the first HDMI/DP sink's ELD.
|
||||
*/
|
||||
struct drm_connector *drm_select_eld(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct drm_connector *connector;
|
||||
struct drm_device *dev = encoder->dev;
|
||||
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head)
|
||||
if (connector->encoder == encoder && connector->eld[0])
|
||||
return connector;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_select_eld);
|
||||
|
||||
/**
|
||||
* drm_detect_hdmi_monitor - detect whether monitor is hdmi.
|
||||
* @edid: monitor EDID information
|
||||
|
||||
@@ -285,6 +285,94 @@ again:
|
||||
}
|
||||
EXPORT_SYMBOL(drm_gem_handle_create);
|
||||
|
||||
|
||||
/**
|
||||
* drm_gem_free_mmap_offset - release a fake mmap offset for an object
|
||||
* @obj: obj in question
|
||||
*
|
||||
* This routine frees fake offsets allocated by drm_gem_create_mmap_offset().
|
||||
*/
|
||||
void
|
||||
drm_gem_free_mmap_offset(struct drm_gem_object *obj)
|
||||
{
|
||||
struct drm_device *dev = obj->dev;
|
||||
struct drm_gem_mm *mm = 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;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_gem_free_mmap_offset);
|
||||
|
||||
/**
|
||||
* drm_gem_create_mmap_offset - create a fake mmap offset for an object
|
||||
* @obj: obj in question
|
||||
*
|
||||
* GEM memory mapping works by handing back to userspace a fake mmap offset
|
||||
* it can use in a subsequent mmap(2) call. The DRM core code then looks
|
||||
* up the object based on the offset and sets up the various memory mapping
|
||||
* structures.
|
||||
*
|
||||
* This routine allocates and attaches a fake offset for @obj.
|
||||
*/
|
||||
int
|
||||
drm_gem_create_mmap_offset(struct drm_gem_object *obj)
|
||||
{
|
||||
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 = 0;
|
||||
|
||||
/* Set the object up for mmap'ing */
|
||||
list = &obj->map_list;
|
||||
list->map = kzalloc(sizeof(struct drm_map_list), GFP_KERNEL);
|
||||
if (!list->map)
|
||||
return -ENOMEM;
|
||||
|
||||
map = list->map;
|
||||
map->type = _DRM_GEM;
|
||||
map->size = obj->size;
|
||||
map->handle = obj;
|
||||
|
||||
/* Get a DRM GEM mmap offset allocated... */
|
||||
list->file_offset_node = drm_mm_search_free(&mm->offset_manager,
|
||||
obj->size / PAGE_SIZE, 0, 0);
|
||||
|
||||
if (!list->file_offset_node) {
|
||||
DRM_ERROR("failed to allocate offset for bo %d\n", obj->name);
|
||||
ret = -ENOSPC;
|
||||
goto out_free_list;
|
||||
}
|
||||
|
||||
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 out_free_list;
|
||||
}
|
||||
|
||||
list->hash.key = list->file_offset_node->start;
|
||||
ret = drm_ht_insert_item(&mm->offset_hash, &list->hash);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to add to map hash\n");
|
||||
goto out_free_mm;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_free_mm:
|
||||
drm_mm_put_block(list->file_offset_node);
|
||||
out_free_list:
|
||||
kfree(list->map);
|
||||
list->map = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_gem_create_mmap_offset);
|
||||
|
||||
/** Returns a reference to the object named by the handle. */
|
||||
struct drm_gem_object *
|
||||
drm_gem_object_lookup(struct drm_device *dev, struct drm_file *filp,
|
||||
|
||||
@@ -95,7 +95,6 @@ int drm_proc_create_files(struct drm_info_list *files, int count,
|
||||
struct drm_device *dev = minor->dev;
|
||||
struct proc_dir_entry *ent;
|
||||
struct drm_info_node *tmp;
|
||||
char name[64];
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
@@ -118,7 +117,7 @@ int drm_proc_create_files(struct drm_info_list *files, int count,
|
||||
&drm_proc_fops, tmp);
|
||||
if (!ent) {
|
||||
DRM_ERROR("Cannot create /proc/dri/%s/%s\n",
|
||||
name, files[i].name);
|
||||
root->name, files[i].name);
|
||||
list_del(&tmp->list);
|
||||
kfree(tmp);
|
||||
ret = -1;
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
config DRM_EXYNOS
|
||||
tristate "DRM Support for Samsung SoC EXYNOS Series"
|
||||
depends on DRM && PLAT_SAMSUNG
|
||||
default n
|
||||
select DRM_KMS_HELPER
|
||||
select FB_CFB_FILLRECT
|
||||
select FB_CFB_COPYAREA
|
||||
select FB_CFB_IMAGEBLIT
|
||||
select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE
|
||||
help
|
||||
Choose this option if you have a Samsung SoC EXYNOS chipset.
|
||||
If M is selected the module will be called exynosdrm.
|
||||
|
||||
config DRM_EXYNOS_FIMD
|
||||
tristate "Exynos DRM FIMD"
|
||||
depends on DRM_EXYNOS
|
||||
default n
|
||||
help
|
||||
Choose this option if you want to use Exynos FIMD for DRM.
|
||||
If M is selected, the module will be called exynos_drm_fimd
|
||||
@@ -0,0 +1,11 @@
|
||||
#
|
||||
# Makefile for the drm device driver. This driver provides support for the
|
||||
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
|
||||
|
||||
ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/exynos
|
||||
exynosdrm-y := exynos_drm_drv.o exynos_drm_encoder.o exynos_drm_connector.o \
|
||||
exynos_drm_crtc.o exynos_drm_fbdev.o exynos_drm_fb.o \
|
||||
exynos_drm_buf.o exynos_drm_gem.o exynos_drm_core.o
|
||||
|
||||
obj-$(CONFIG_DRM_EXYNOS) += exynosdrm.o
|
||||
obj-$(CONFIG_DRM_EXYNOS_FIMD) += exynos_drm_fimd.o
|
||||
@@ -0,0 +1,110 @@
|
||||
/* exynos_drm_buf.c
|
||||
*
|
||||
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
|
||||
* Author: Inki Dae <inki.dae@samsung.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "drmP.h"
|
||||
#include "drm.h"
|
||||
|
||||
#include "exynos_drm_drv.h"
|
||||
#include "exynos_drm_buf.h"
|
||||
|
||||
static DEFINE_MUTEX(exynos_drm_buf_lock);
|
||||
|
||||
static int lowlevel_buffer_allocate(struct drm_device *dev,
|
||||
struct exynos_drm_buf_entry *entry)
|
||||
{
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
entry->vaddr = dma_alloc_writecombine(dev->dev, entry->size,
|
||||
(dma_addr_t *)&entry->paddr, GFP_KERNEL);
|
||||
if (!entry->paddr) {
|
||||
DRM_ERROR("failed to allocate buffer.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
DRM_DEBUG_KMS("allocated : vaddr(0x%x), paddr(0x%x), size(0x%x)\n",
|
||||
(unsigned int)entry->vaddr, entry->paddr, entry->size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lowlevel_buffer_deallocate(struct drm_device *dev,
|
||||
struct exynos_drm_buf_entry *entry)
|
||||
{
|
||||
DRM_DEBUG_KMS("%s.\n", __FILE__);
|
||||
|
||||
if (entry->paddr && entry->vaddr && entry->size)
|
||||
dma_free_writecombine(dev->dev, entry->size, entry->vaddr,
|
||||
entry->paddr);
|
||||
else
|
||||
DRM_DEBUG_KMS("entry data is null.\n");
|
||||
}
|
||||
|
||||
struct exynos_drm_buf_entry *exynos_drm_buf_create(struct drm_device *dev,
|
||||
unsigned int size)
|
||||
{
|
||||
struct exynos_drm_buf_entry *entry;
|
||||
|
||||
DRM_DEBUG_KMS("%s.\n", __FILE__);
|
||||
|
||||
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
|
||||
if (!entry) {
|
||||
DRM_ERROR("failed to allocate exynos_drm_buf_entry.\n");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
entry->size = size;
|
||||
|
||||
/*
|
||||
* allocate memory region with size and set the memory information
|
||||
* to vaddr and paddr of a entry object.
|
||||
*/
|
||||
if (lowlevel_buffer_allocate(dev, entry) < 0) {
|
||||
kfree(entry);
|
||||
entry = NULL;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
void exynos_drm_buf_destroy(struct drm_device *dev,
|
||||
struct exynos_drm_buf_entry *entry)
|
||||
{
|
||||
DRM_DEBUG_KMS("%s.\n", __FILE__);
|
||||
|
||||
if (!entry) {
|
||||
DRM_DEBUG_KMS("entry is null.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
lowlevel_buffer_deallocate(dev, entry);
|
||||
|
||||
kfree(entry);
|
||||
entry = NULL;
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
|
||||
MODULE_DESCRIPTION("Samsung SoC DRM Buffer Management Module");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -0,0 +1,53 @@
|
||||
/* exynos_drm_buf.h
|
||||
*
|
||||
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
|
||||
* Author: Inki Dae <inki.dae@samsung.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _EXYNOS_DRM_BUF_H_
|
||||
#define _EXYNOS_DRM_BUF_H_
|
||||
|
||||
/*
|
||||
* exynos drm buffer entry structure.
|
||||
*
|
||||
* @paddr: physical address of allocated memory.
|
||||
* @vaddr: kernel virtual address of allocated memory.
|
||||
* @size: size of allocated memory.
|
||||
*/
|
||||
struct exynos_drm_buf_entry {
|
||||
dma_addr_t paddr;
|
||||
void __iomem *vaddr;
|
||||
unsigned int size;
|
||||
};
|
||||
|
||||
/* allocate physical memory. */
|
||||
struct exynos_drm_buf_entry *exynos_drm_buf_create(struct drm_device *dev,
|
||||
unsigned int size);
|
||||
|
||||
/* get physical memory information of a drm framebuffer. */
|
||||
struct exynos_drm_buf_entry *exynos_drm_fb_get_buf(struct drm_framebuffer *fb);
|
||||
|
||||
/* remove allocated physical memory. */
|
||||
void exynos_drm_buf_destroy(struct drm_device *dev,
|
||||
struct exynos_drm_buf_entry *entry);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
|
||||
* Authors:
|
||||
* Inki Dae <inki.dae@samsung.com>
|
||||
* Joonyoung Shim <jy0922.shim@samsung.com>
|
||||
* Seung-Woo Kim <sw0312.kim@samsung.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "drmP.h"
|
||||
#include "drm_crtc_helper.h"
|
||||
|
||||
#include "exynos_drm_drv.h"
|
||||
#include "exynos_drm_encoder.h"
|
||||
|
||||
#define MAX_EDID 256
|
||||
#define to_exynos_connector(x) container_of(x, struct exynos_drm_connector,\
|
||||
drm_connector)
|
||||
|
||||
struct exynos_drm_connector {
|
||||
struct drm_connector drm_connector;
|
||||
};
|
||||
|
||||
/* convert exynos_video_timings to drm_display_mode */
|
||||
static inline void
|
||||
convert_to_display_mode(struct drm_display_mode *mode,
|
||||
struct fb_videomode *timing)
|
||||
{
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
mode->clock = timing->pixclock / 1000;
|
||||
|
||||
mode->hdisplay = timing->xres;
|
||||
mode->hsync_start = mode->hdisplay + timing->left_margin;
|
||||
mode->hsync_end = mode->hsync_start + timing->hsync_len;
|
||||
mode->htotal = mode->hsync_end + timing->right_margin;
|
||||
|
||||
mode->vdisplay = timing->yres;
|
||||
mode->vsync_start = mode->vdisplay + timing->upper_margin;
|
||||
mode->vsync_end = mode->vsync_start + timing->vsync_len;
|
||||
mode->vtotal = mode->vsync_end + timing->lower_margin;
|
||||
}
|
||||
|
||||
/* convert drm_display_mode to exynos_video_timings */
|
||||
static inline void
|
||||
convert_to_video_timing(struct fb_videomode *timing,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
memset(timing, 0, sizeof(*timing));
|
||||
|
||||
timing->pixclock = mode->clock * 1000;
|
||||
timing->refresh = mode->vrefresh;
|
||||
|
||||
timing->xres = mode->hdisplay;
|
||||
timing->left_margin = mode->hsync_start - mode->hdisplay;
|
||||
timing->hsync_len = mode->hsync_end - mode->hsync_start;
|
||||
timing->right_margin = mode->htotal - mode->hsync_end;
|
||||
|
||||
timing->yres = mode->vdisplay;
|
||||
timing->upper_margin = mode->vsync_start - mode->vdisplay;
|
||||
timing->vsync_len = mode->vsync_end - mode->vsync_start;
|
||||
timing->lower_margin = mode->vtotal - mode->vsync_end;
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
|
||||
timing->vmode = FB_VMODE_INTERLACED;
|
||||
else
|
||||
timing->vmode = FB_VMODE_NONINTERLACED;
|
||||
|
||||
if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
|
||||
timing->vmode |= FB_VMODE_DOUBLE;
|
||||
}
|
||||
|
||||
static int exynos_drm_connector_get_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct exynos_drm_manager *manager =
|
||||
exynos_drm_get_manager(connector->encoder);
|
||||
struct exynos_drm_display *display = manager->display;
|
||||
unsigned int count;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (!display) {
|
||||
DRM_DEBUG_KMS("display is null.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* if get_edid() exists then get_edid() callback of hdmi side
|
||||
* is called to get edid data through i2c interface else
|
||||
* get timing from the FIMD driver(display controller).
|
||||
*
|
||||
* P.S. in case of lcd panel, count is always 1 if success
|
||||
* because lcd panel has only one mode.
|
||||
*/
|
||||
if (display->get_edid) {
|
||||
int ret;
|
||||
void *edid;
|
||||
|
||||
edid = kzalloc(MAX_EDID, GFP_KERNEL);
|
||||
if (!edid) {
|
||||
DRM_ERROR("failed to allocate edid\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = display->get_edid(manager->dev, connector,
|
||||
edid, MAX_EDID);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("failed to get edid data.\n");
|
||||
kfree(edid);
|
||||
edid = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
drm_mode_connector_update_edid_property(connector, edid);
|
||||
count = drm_add_edid_modes(connector, edid);
|
||||
|
||||
kfree(connector->display_info.raw_edid);
|
||||
connector->display_info.raw_edid = edid;
|
||||
} else {
|
||||
struct drm_display_mode *mode = drm_mode_create(connector->dev);
|
||||
struct fb_videomode *timing;
|
||||
|
||||
if (display->get_timing)
|
||||
timing = display->get_timing(manager->dev);
|
||||
else {
|
||||
drm_mode_destroy(connector->dev, mode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
convert_to_display_mode(mode, timing);
|
||||
|
||||
mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
|
||||
drm_mode_set_name(mode);
|
||||
drm_mode_probed_add(connector, mode);
|
||||
|
||||
count = 1;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int exynos_drm_connector_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct exynos_drm_manager *manager =
|
||||
exynos_drm_get_manager(connector->encoder);
|
||||
struct exynos_drm_display *display = manager->display;
|
||||
struct fb_videomode timing;
|
||||
int ret = MODE_BAD;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
convert_to_video_timing(&timing, mode);
|
||||
|
||||
if (display && display->check_timing)
|
||||
if (!display->check_timing(manager->dev, (void *)&timing))
|
||||
ret = MODE_OK;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct drm_encoder *exynos_drm_best_encoder(struct drm_connector *connector)
|
||||
{
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
return connector->encoder;
|
||||
}
|
||||
|
||||
static struct drm_connector_helper_funcs exynos_connector_helper_funcs = {
|
||||
.get_modes = exynos_drm_connector_get_modes,
|
||||
.mode_valid = exynos_drm_connector_mode_valid,
|
||||
.best_encoder = exynos_drm_best_encoder,
|
||||
};
|
||||
|
||||
/* get detection status of display device. */
|
||||
static enum drm_connector_status
|
||||
exynos_drm_connector_detect(struct drm_connector *connector, bool force)
|
||||
{
|
||||
struct exynos_drm_manager *manager =
|
||||
exynos_drm_get_manager(connector->encoder);
|
||||
struct exynos_drm_display *display = manager->display;
|
||||
enum drm_connector_status status = connector_status_disconnected;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
if (display && display->is_connected) {
|
||||
if (display->is_connected(manager->dev))
|
||||
status = connector_status_connected;
|
||||
else
|
||||
status = connector_status_disconnected;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void exynos_drm_connector_destroy(struct drm_connector *connector)
|
||||
{
|
||||
struct exynos_drm_connector *exynos_connector =
|
||||
to_exynos_connector(connector);
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
drm_sysfs_connector_remove(connector);
|
||||
drm_connector_cleanup(connector);
|
||||
kfree(exynos_connector);
|
||||
}
|
||||
|
||||
static struct drm_connector_funcs exynos_connector_funcs = {
|
||||
.dpms = drm_helper_connector_dpms,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.detect = exynos_drm_connector_detect,
|
||||
.destroy = exynos_drm_connector_destroy,
|
||||
};
|
||||
|
||||
struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
|
||||
struct drm_encoder *encoder)
|
||||
{
|
||||
struct exynos_drm_connector *exynos_connector;
|
||||
struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
|
||||
struct drm_connector *connector;
|
||||
int type;
|
||||
int err;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
exynos_connector = kzalloc(sizeof(*exynos_connector), GFP_KERNEL);
|
||||
if (!exynos_connector) {
|
||||
DRM_ERROR("failed to allocate connector\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
connector = &exynos_connector->drm_connector;
|
||||
|
||||
switch (manager->display->type) {
|
||||
case EXYNOS_DISPLAY_TYPE_HDMI:
|
||||
type = DRM_MODE_CONNECTOR_HDMIA;
|
||||
break;
|
||||
default:
|
||||
type = DRM_MODE_CONNECTOR_Unknown;
|
||||
break;
|
||||
}
|
||||
|
||||
drm_connector_init(dev, connector, &exynos_connector_funcs, type);
|
||||
drm_connector_helper_add(connector, &exynos_connector_helper_funcs);
|
||||
|
||||
err = drm_sysfs_connector_add(connector);
|
||||
if (err)
|
||||
goto err_connector;
|
||||
|
||||
connector->encoder = encoder;
|
||||
err = drm_mode_connector_attach_encoder(connector, encoder);
|
||||
if (err) {
|
||||
DRM_ERROR("failed to attach a connector to a encoder\n");
|
||||
goto err_sysfs;
|
||||
}
|
||||
|
||||
DRM_DEBUG_KMS("connector has been created\n");
|
||||
|
||||
return connector;
|
||||
|
||||
err_sysfs:
|
||||
drm_sysfs_connector_remove(connector);
|
||||
err_connector:
|
||||
drm_connector_cleanup(connector);
|
||||
kfree(exynos_connector);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
|
||||
MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
|
||||
MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>");
|
||||
MODULE_DESCRIPTION("Samsung SoC DRM Connector Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
|
||||
* Authors:
|
||||
* Inki Dae <inki.dae@samsung.com>
|
||||
* Joonyoung Shim <jy0922.shim@samsung.com>
|
||||
* Seung-Woo Kim <sw0312.kim@samsung.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _EXYNOS_DRM_CONNECTOR_H_
|
||||
#define _EXYNOS_DRM_CONNECTOR_H_
|
||||
|
||||
struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
|
||||
struct drm_encoder *encoder);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,272 @@
|
||||
/* exynos_drm_core.c
|
||||
*
|
||||
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
|
||||
* Author:
|
||||
* Inki Dae <inki.dae@samsung.com>
|
||||
* Joonyoung Shim <jy0922.shim@samsung.com>
|
||||
* Seung-Woo Kim <sw0312.kim@samsung.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "drmP.h"
|
||||
#include "exynos_drm_drv.h"
|
||||
#include "exynos_drm_encoder.h"
|
||||
#include "exynos_drm_connector.h"
|
||||
#include "exynos_drm_fbdev.h"
|
||||
|
||||
static DEFINE_MUTEX(exynos_drm_mutex);
|
||||
static LIST_HEAD(exynos_drm_subdrv_list);
|
||||
static struct drm_device *drm_dev;
|
||||
|
||||
static int exynos_drm_subdrv_probe(struct drm_device *dev,
|
||||
struct exynos_drm_subdrv *subdrv)
|
||||
{
|
||||
struct drm_encoder *encoder;
|
||||
struct drm_connector *connector;
|
||||
|
||||
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
||||
|
||||
if (subdrv->probe) {
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* this probe callback would be called by sub driver
|
||||
* after setting of all resources to this sub driver,
|
||||
* such as clock, irq and register map are done or by load()
|
||||
* of exynos drm driver.
|
||||
*
|
||||
* P.S. note that this driver is considered for modularization.
|
||||
*/
|
||||
ret = subdrv->probe(dev, subdrv->manager.dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* create and initialize a encoder for this sub driver. */
|
||||
encoder = exynos_drm_encoder_create(dev, &subdrv->manager,
|
||||
(1 << MAX_CRTC) - 1);
|
||||
if (!encoder) {
|
||||
DRM_ERROR("failed to create encoder\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
/*
|
||||
* create and initialize a connector for this sub driver and
|
||||
* attach the encoder created above to the connector.
|
||||
*/
|
||||
connector = exynos_drm_connector_create(dev, encoder);
|
||||
if (!connector) {
|
||||
DRM_ERROR("failed to create connector\n");
|
||||
encoder->funcs->destroy(encoder);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
subdrv->encoder = encoder;
|
||||
subdrv->connector = connector;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void exynos_drm_subdrv_remove(struct drm_device *dev,
|
||||
struct exynos_drm_subdrv *subdrv)
|
||||
{
|
||||
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
||||
|
||||
if (subdrv->remove)
|
||||
subdrv->remove(dev);
|
||||
|
||||
if (subdrv->encoder) {
|
||||
struct drm_encoder *encoder = subdrv->encoder;
|
||||
encoder->funcs->destroy(encoder);
|
||||
subdrv->encoder = NULL;
|
||||
}
|
||||
|
||||
if (subdrv->connector) {
|
||||
struct drm_connector *connector = subdrv->connector;
|
||||
connector->funcs->destroy(connector);
|
||||
subdrv->connector = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int exynos_drm_device_register(struct drm_device *dev)
|
||||
{
|
||||
struct exynos_drm_subdrv *subdrv, *n;
|
||||
int err;
|
||||
|
||||
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
||||
|
||||
if (!dev)
|
||||
return -EINVAL;
|
||||
|
||||
if (drm_dev) {
|
||||
DRM_ERROR("Already drm device were registered\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
mutex_lock(&exynos_drm_mutex);
|
||||
list_for_each_entry_safe(subdrv, n, &exynos_drm_subdrv_list, list) {
|
||||
err = exynos_drm_subdrv_probe(dev, subdrv);
|
||||
if (err) {
|
||||
DRM_DEBUG("exynos drm subdrv probe failed.\n");
|
||||
list_del(&subdrv->list);
|
||||
}
|
||||
}
|
||||
|
||||
drm_dev = dev;
|
||||
mutex_unlock(&exynos_drm_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(exynos_drm_device_register);
|
||||
|
||||
int exynos_drm_device_unregister(struct drm_device *dev)
|
||||
{
|
||||
struct exynos_drm_subdrv *subdrv;
|
||||
|
||||
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
||||
|
||||
if (!dev || dev != drm_dev) {
|
||||
WARN(1, "Unexpected drm device unregister!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&exynos_drm_mutex);
|
||||
list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list)
|
||||
exynos_drm_subdrv_remove(dev, subdrv);
|
||||
|
||||
drm_dev = NULL;
|
||||
mutex_unlock(&exynos_drm_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(exynos_drm_device_unregister);
|
||||
|
||||
static int exynos_drm_mode_group_reinit(struct drm_device *dev)
|
||||
{
|
||||
struct drm_mode_group *group = &dev->primary->mode_group;
|
||||
uint32_t *id_list = group->id_list;
|
||||
int ret;
|
||||
|
||||
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
||||
|
||||
ret = drm_mode_group_init_legacy_group(dev, group);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
kfree(id_list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv)
|
||||
{
|
||||
int err;
|
||||
|
||||
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
||||
|
||||
if (!subdrv)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&exynos_drm_mutex);
|
||||
if (drm_dev) {
|
||||
err = exynos_drm_subdrv_probe(drm_dev, subdrv);
|
||||
if (err) {
|
||||
DRM_ERROR("failed to probe exynos drm subdrv\n");
|
||||
mutex_unlock(&exynos_drm_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* if any specific driver such as fimd or hdmi driver called
|
||||
* exynos_drm_subdrv_register() later than drm_load(),
|
||||
* the fb helper should be re-initialized and re-configured.
|
||||
*/
|
||||
err = exynos_drm_fbdev_reinit(drm_dev);
|
||||
if (err) {
|
||||
DRM_ERROR("failed to reinitialize exynos drm fbdev\n");
|
||||
exynos_drm_subdrv_remove(drm_dev, subdrv);
|
||||
mutex_unlock(&exynos_drm_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = exynos_drm_mode_group_reinit(drm_dev);
|
||||
if (err) {
|
||||
DRM_ERROR("failed to reinitialize mode group\n");
|
||||
exynos_drm_fbdev_fini(drm_dev);
|
||||
exynos_drm_subdrv_remove(drm_dev, subdrv);
|
||||
mutex_unlock(&exynos_drm_mutex);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
subdrv->drm_dev = drm_dev;
|
||||
|
||||
list_add_tail(&subdrv->list, &exynos_drm_subdrv_list);
|
||||
mutex_unlock(&exynos_drm_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(exynos_drm_subdrv_register);
|
||||
|
||||
int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv)
|
||||
{
|
||||
int ret = -EFAULT;
|
||||
|
||||
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
||||
|
||||
if (!subdrv) {
|
||||
DRM_DEBUG("Unexpected exynos drm subdrv unregister!\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
mutex_lock(&exynos_drm_mutex);
|
||||
if (drm_dev) {
|
||||
exynos_drm_subdrv_remove(drm_dev, subdrv);
|
||||
list_del(&subdrv->list);
|
||||
|
||||
/*
|
||||
* fb helper should be updated once a sub driver is released
|
||||
* to re-configure crtc and connector and also to re-setup
|
||||
* drm framebuffer.
|
||||
*/
|
||||
ret = exynos_drm_fbdev_reinit(drm_dev);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("failed fb helper reinit.\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = exynos_drm_mode_group_reinit(drm_dev);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("failed drm mode group reinit.\n");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
fail:
|
||||
mutex_unlock(&exynos_drm_mutex);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(exynos_drm_subdrv_unregister);
|
||||
|
||||
MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
|
||||
MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
|
||||
MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>");
|
||||
MODULE_DESCRIPTION("Samsung SoC DRM Core Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -0,0 +1,381 @@
|
||||
/* exynos_drm_crtc.c
|
||||
*
|
||||
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
|
||||
* Authors:
|
||||
* Inki Dae <inki.dae@samsung.com>
|
||||
* Joonyoung Shim <jy0922.shim@samsung.com>
|
||||
* Seung-Woo Kim <sw0312.kim@samsung.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "drmP.h"
|
||||
#include "drm_crtc_helper.h"
|
||||
|
||||
#include "exynos_drm_drv.h"
|
||||
#include "exynos_drm_fb.h"
|
||||
#include "exynos_drm_encoder.h"
|
||||
#include "exynos_drm_buf.h"
|
||||
|
||||
#define to_exynos_crtc(x) container_of(x, struct exynos_drm_crtc,\
|
||||
drm_crtc)
|
||||
|
||||
/*
|
||||
* Exynos specific crtc postion structure.
|
||||
*
|
||||
* @fb_x: offset x on a framebuffer to be displyed
|
||||
* - the unit is screen coordinates.
|
||||
* @fb_y: offset y on a framebuffer to be displayed
|
||||
* - the unit is screen coordinates.
|
||||
* @crtc_x: offset x on hardware screen.
|
||||
* @crtc_y: offset y on hardware screen.
|
||||
* @crtc_w: width of hardware screen.
|
||||
* @crtc_h: height of hardware screen.
|
||||
*/
|
||||
struct exynos_drm_crtc_pos {
|
||||
unsigned int fb_x;
|
||||
unsigned int fb_y;
|
||||
unsigned int crtc_x;
|
||||
unsigned int crtc_y;
|
||||
unsigned int crtc_w;
|
||||
unsigned int crtc_h;
|
||||
};
|
||||
|
||||
/*
|
||||
* Exynos specific crtc structure.
|
||||
*
|
||||
* @drm_crtc: crtc object.
|
||||
* @overlay: contain information common to display controller and hdmi and
|
||||
* contents of this overlay object would be copied to sub driver size.
|
||||
* @pipe: a crtc index created at load() with a new crtc object creation
|
||||
* and the crtc object would be set to private->crtc array
|
||||
* to get a crtc object corresponding to this pipe from private->crtc
|
||||
* array when irq interrupt occured. the reason of using this pipe is that
|
||||
* drm framework doesn't support multiple irq yet.
|
||||
* we can refer to the crtc to current hardware interrupt occured through
|
||||
* this pipe value.
|
||||
*/
|
||||
struct exynos_drm_crtc {
|
||||
struct drm_crtc drm_crtc;
|
||||
struct exynos_drm_overlay overlay;
|
||||
unsigned int pipe;
|
||||
};
|
||||
|
||||
static void exynos_drm_crtc_apply(struct drm_crtc *crtc)
|
||||
{
|
||||
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
|
||||
struct exynos_drm_overlay *overlay = &exynos_crtc->overlay;
|
||||
|
||||
exynos_drm_fn_encoder(crtc, overlay,
|
||||
exynos_drm_encoder_crtc_mode_set);
|
||||
exynos_drm_fn_encoder(crtc, NULL, exynos_drm_encoder_crtc_commit);
|
||||
}
|
||||
|
||||
static int exynos_drm_overlay_update(struct exynos_drm_overlay *overlay,
|
||||
struct drm_framebuffer *fb,
|
||||
struct drm_display_mode *mode,
|
||||
struct exynos_drm_crtc_pos *pos)
|
||||
{
|
||||
struct exynos_drm_buf_entry *entry;
|
||||
unsigned int actual_w;
|
||||
unsigned int actual_h;
|
||||
|
||||
entry = exynos_drm_fb_get_buf(fb);
|
||||
if (!entry) {
|
||||
DRM_LOG_KMS("entry is null.\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
overlay->paddr = entry->paddr;
|
||||
overlay->vaddr = entry->vaddr;
|
||||
|
||||
DRM_DEBUG_KMS("vaddr = 0x%lx, paddr = 0x%lx\n",
|
||||
(unsigned long)overlay->vaddr,
|
||||
(unsigned long)overlay->paddr);
|
||||
|
||||
actual_w = min((mode->hdisplay - pos->crtc_x), pos->crtc_w);
|
||||
actual_h = min((mode->vdisplay - pos->crtc_y), pos->crtc_h);
|
||||
|
||||
/* set drm framebuffer data. */
|
||||
overlay->fb_x = pos->fb_x;
|
||||
overlay->fb_y = pos->fb_y;
|
||||
overlay->fb_width = fb->width;
|
||||
overlay->fb_height = fb->height;
|
||||
overlay->bpp = fb->bits_per_pixel;
|
||||
overlay->pitch = fb->pitch;
|
||||
|
||||
/* set overlay range to be displayed. */
|
||||
overlay->crtc_x = pos->crtc_x;
|
||||
overlay->crtc_y = pos->crtc_y;
|
||||
overlay->crtc_width = actual_w;
|
||||
overlay->crtc_height = actual_h;
|
||||
|
||||
/* set drm mode data. */
|
||||
overlay->mode_width = mode->hdisplay;
|
||||
overlay->mode_height = mode->vdisplay;
|
||||
overlay->refresh = mode->vrefresh;
|
||||
overlay->scan_flag = mode->flags;
|
||||
|
||||
DRM_DEBUG_KMS("overlay : offset_x/y(%d,%d), width/height(%d,%d)",
|
||||
overlay->crtc_x, overlay->crtc_y,
|
||||
overlay->crtc_width, overlay->crtc_height);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int exynos_drm_crtc_update(struct drm_crtc *crtc)
|
||||
{
|
||||
struct exynos_drm_crtc *exynos_crtc;
|
||||
struct exynos_drm_overlay *overlay;
|
||||
struct exynos_drm_crtc_pos pos;
|
||||
struct drm_display_mode *mode = &crtc->mode;
|
||||
struct drm_framebuffer *fb = crtc->fb;
|
||||
|
||||
if (!mode || !fb)
|
||||
return -EINVAL;
|
||||
|
||||
exynos_crtc = to_exynos_crtc(crtc);
|
||||
overlay = &exynos_crtc->overlay;
|
||||
|
||||
memset(&pos, 0, sizeof(struct exynos_drm_crtc_pos));
|
||||
|
||||
/* it means the offset of framebuffer to be displayed. */
|
||||
pos.fb_x = crtc->x;
|
||||
pos.fb_y = crtc->y;
|
||||
|
||||
/* OSD position to be displayed. */
|
||||
pos.crtc_x = 0;
|
||||
pos.crtc_y = 0;
|
||||
pos.crtc_w = fb->width - crtc->x;
|
||||
pos.crtc_h = fb->height - crtc->y;
|
||||
|
||||
return exynos_drm_overlay_update(overlay, crtc->fb, mode, &pos);
|
||||
}
|
||||
|
||||
static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
|
||||
{
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
/* TODO */
|
||||
}
|
||||
|
||||
static void exynos_drm_crtc_prepare(struct drm_crtc *crtc)
|
||||
{
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
/* drm framework doesn't check NULL. */
|
||||
}
|
||||
|
||||
static void exynos_drm_crtc_commit(struct drm_crtc *crtc)
|
||||
{
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
/* drm framework doesn't check NULL. */
|
||||
}
|
||||
|
||||
static bool
|
||||
exynos_drm_crtc_mode_fixup(struct drm_crtc *crtc,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
/* drm framework doesn't check NULL */
|
||||
return true;
|
||||
}
|
||||
|
||||
static int
|
||||
exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode, int x, int y,
|
||||
struct drm_framebuffer *old_fb)
|
||||
{
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
mode = adjusted_mode;
|
||||
|
||||
return exynos_drm_crtc_update(crtc);
|
||||
}
|
||||
|
||||
static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
|
||||
struct drm_framebuffer *old_fb)
|
||||
{
|
||||
int ret;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
ret = exynos_drm_crtc_update(crtc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
exynos_drm_crtc_apply(crtc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void exynos_drm_crtc_load_lut(struct drm_crtc *crtc)
|
||||
{
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
/* drm framework doesn't check NULL */
|
||||
}
|
||||
|
||||
static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = {
|
||||
.dpms = exynos_drm_crtc_dpms,
|
||||
.prepare = exynos_drm_crtc_prepare,
|
||||
.commit = exynos_drm_crtc_commit,
|
||||
.mode_fixup = exynos_drm_crtc_mode_fixup,
|
||||
.mode_set = exynos_drm_crtc_mode_set,
|
||||
.mode_set_base = exynos_drm_crtc_mode_set_base,
|
||||
.load_lut = exynos_drm_crtc_load_lut,
|
||||
};
|
||||
|
||||
static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,
|
||||
struct drm_framebuffer *fb,
|
||||
struct drm_pending_vblank_event *event)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct exynos_drm_private *dev_priv = dev->dev_private;
|
||||
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
|
||||
struct drm_framebuffer *old_fb = crtc->fb;
|
||||
int ret = -EINVAL;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
|
||||
if (event) {
|
||||
/*
|
||||
* the pipe from user always is 0 so we can set pipe number
|
||||
* of current owner to event.
|
||||
*/
|
||||
event->pipe = exynos_crtc->pipe;
|
||||
|
||||
list_add_tail(&event->base.link,
|
||||
&dev_priv->pageflip_event_list);
|
||||
|
||||
ret = drm_vblank_get(dev, exynos_crtc->pipe);
|
||||
if (ret) {
|
||||
DRM_DEBUG("failed to acquire vblank counter\n");
|
||||
list_del(&event->base.link);
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
crtc->fb = fb;
|
||||
ret = exynos_drm_crtc_update(crtc);
|
||||
if (ret) {
|
||||
crtc->fb = old_fb;
|
||||
drm_vblank_put(dev, exynos_crtc->pipe);
|
||||
list_del(&event->base.link);
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* the values related to a buffer of the drm framebuffer
|
||||
* to be applied should be set at here. because these values
|
||||
* first, are set to shadow registers and then to
|
||||
* real registers at vsync front porch period.
|
||||
*/
|
||||
exynos_drm_crtc_apply(crtc);
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void exynos_drm_crtc_destroy(struct drm_crtc *crtc)
|
||||
{
|
||||
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
|
||||
struct exynos_drm_private *private = crtc->dev->dev_private;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
private->crtc[exynos_crtc->pipe] = NULL;
|
||||
|
||||
drm_crtc_cleanup(crtc);
|
||||
kfree(exynos_crtc);
|
||||
}
|
||||
|
||||
static struct drm_crtc_funcs exynos_crtc_funcs = {
|
||||
.set_config = drm_crtc_helper_set_config,
|
||||
.page_flip = exynos_drm_crtc_page_flip,
|
||||
.destroy = exynos_drm_crtc_destroy,
|
||||
};
|
||||
|
||||
struct exynos_drm_overlay *get_exynos_drm_overlay(struct drm_device *dev,
|
||||
struct drm_crtc *crtc)
|
||||
{
|
||||
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
|
||||
|
||||
return &exynos_crtc->overlay;
|
||||
}
|
||||
|
||||
int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
|
||||
{
|
||||
struct exynos_drm_crtc *exynos_crtc;
|
||||
struct exynos_drm_private *private = dev->dev_private;
|
||||
struct drm_crtc *crtc;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
exynos_crtc = kzalloc(sizeof(*exynos_crtc), GFP_KERNEL);
|
||||
if (!exynos_crtc) {
|
||||
DRM_ERROR("failed to allocate exynos crtc\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
exynos_crtc->pipe = nr;
|
||||
crtc = &exynos_crtc->drm_crtc;
|
||||
|
||||
private->crtc[nr] = crtc;
|
||||
|
||||
drm_crtc_init(dev, crtc, &exynos_crtc_funcs);
|
||||
drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int crtc)
|
||||
{
|
||||
struct exynos_drm_private *private = dev->dev_private;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
exynos_drm_fn_encoder(private->crtc[crtc], &crtc,
|
||||
exynos_drm_enable_vblank);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc)
|
||||
{
|
||||
struct exynos_drm_private *private = dev->dev_private;
|
||||
|
||||
DRM_DEBUG_KMS("%s\n", __FILE__);
|
||||
|
||||
exynos_drm_fn_encoder(private->crtc[crtc], &crtc,
|
||||
exynos_drm_disable_vblank);
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
|
||||
MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
|
||||
MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>");
|
||||
MODULE_DESCRIPTION("Samsung SoC DRM CRTC Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -0,0 +1,38 @@
|
||||
/* exynos_drm_crtc.h
|
||||
*
|
||||
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
|
||||
* Authors:
|
||||
* Inki Dae <inki.dae@samsung.com>
|
||||
* Joonyoung Shim <jy0922.shim@samsung.com>
|
||||
* Seung-Woo Kim <sw0312.kim@samsung.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _EXYNOS_DRM_CRTC_H_
|
||||
#define _EXYNOS_DRM_CRTC_H_
|
||||
|
||||
struct exynos_drm_overlay *get_exynos_drm_overlay(struct drm_device *dev,
|
||||
struct drm_crtc *crtc);
|
||||
int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr);
|
||||
int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int crtc);
|
||||
void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
|
||||
* Authors:
|
||||
* Inki Dae <inki.dae@samsung.com>
|
||||
* Joonyoung Shim <jy0922.shim@samsung.com>
|
||||
* Seung-Woo Kim <sw0312.kim@samsung.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "drmP.h"
|
||||
#include "drm.h"
|
||||
|
||||
#include <drm/exynos_drm.h>
|
||||
|
||||
#include "exynos_drm_drv.h"
|
||||
#include "exynos_drm_crtc.h"
|
||||
#include "exynos_drm_fbdev.h"
|
||||
#include "exynos_drm_fb.h"
|
||||
#include "exynos_drm_gem.h"
|
||||
|
||||
#define DRIVER_NAME "exynos-drm"
|
||||
#define DRIVER_DESC "Samsung SoC DRM"
|
||||
#define DRIVER_DATE "20110530"
|
||||
#define DRIVER_MAJOR 1
|
||||
#define DRIVER_MINOR 0
|
||||
|
||||
static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
|
||||
{
|
||||
struct exynos_drm_private *private;
|
||||
int ret;
|
||||
int nr;
|
||||
|
||||
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
||||
|
||||
private = kzalloc(sizeof(struct exynos_drm_private), GFP_KERNEL);
|
||||
if (!private) {
|
||||
DRM_ERROR("failed to allocate private\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&private->pageflip_event_list);
|
||||
dev->dev_private = (void *)private;
|
||||
|
||||
drm_mode_config_init(dev);
|
||||
|
||||
exynos_drm_mode_config_init(dev);
|
||||
|
||||
/*
|
||||
* EXYNOS4 is enough to have two CRTCs and each crtc would be used
|
||||
* without dependency of hardware.
|
||||
*/
|
||||
for (nr = 0; nr < MAX_CRTC; nr++) {
|
||||
ret = exynos_drm_crtc_create(dev, nr);
|
||||
if (ret)
|
||||
goto err_crtc;
|
||||
}
|
||||
|
||||
ret = drm_vblank_init(dev, MAX_CRTC);
|
||||
if (ret)
|
||||
goto err_crtc;
|
||||
|
||||
/*
|
||||
* probe sub drivers such as display controller and hdmi driver,
|
||||
* that were registered at probe() of platform driver
|
||||
* to the sub driver and create encoder and connector for them.
|
||||
*/
|
||||
ret = exynos_drm_device_register(dev);
|
||||
if (ret)
|
||||
goto err_vblank;
|
||||
|
||||
/*
|
||||
* create and configure fb helper and also exynos specific
|
||||
* fbdev object.
|
||||
*/
|
||||
ret = exynos_drm_fbdev_init(dev);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to initialize drm fbdev\n");
|
||||
goto err_drm_device;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_drm_device:
|
||||
exynos_drm_device_unregister(dev);
|
||||
err_vblank:
|
||||
drm_vblank_cleanup(dev);
|
||||
err_crtc:
|
||||
drm_mode_config_cleanup(dev);
|
||||
kfree(private);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int exynos_drm_unload(struct drm_device *dev)
|
||||
{
|
||||
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
||||
|
||||
exynos_drm_fbdev_fini(dev);
|
||||
exynos_drm_device_unregister(dev);
|
||||
drm_vblank_cleanup(dev);
|
||||
drm_mode_config_cleanup(dev);
|
||||
kfree(dev->dev_private);
|
||||
|
||||
dev->dev_private = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void exynos_drm_preclose(struct drm_device *dev,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct exynos_drm_private *dev_priv = dev->dev_private;
|
||||
|
||||
/*
|
||||
* drm framework frees all events at release time,
|
||||
* so private event list should be cleared.
|
||||
*/
|
||||
if (!list_empty(&dev_priv->pageflip_event_list))
|
||||
INIT_LIST_HEAD(&dev_priv->pageflip_event_list);
|
||||
}
|
||||
|
||||
static void exynos_drm_lastclose(struct drm_device *dev)
|
||||
{
|
||||
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
||||
|
||||
exynos_drm_fbdev_restore_mode(dev);
|
||||
}
|
||||
|
||||
static struct vm_operations_struct exynos_drm_gem_vm_ops = {
|
||||
.fault = exynos_drm_gem_fault,
|
||||
.open = drm_gem_vm_open,
|
||||
.close = drm_gem_vm_close,
|
||||
};
|
||||
|
||||
static struct drm_ioctl_desc exynos_ioctls[] = {
|
||||
DRM_IOCTL_DEF_DRV(EXYNOS_GEM_CREATE, exynos_drm_gem_create_ioctl,
|
||||
DRM_UNLOCKED | DRM_AUTH),
|
||||
DRM_IOCTL_DEF_DRV(EXYNOS_GEM_MAP_OFFSET,
|
||||
exynos_drm_gem_map_offset_ioctl, DRM_UNLOCKED |
|
||||
DRM_AUTH),
|
||||
DRM_IOCTL_DEF_DRV(EXYNOS_GEM_MMAP,
|
||||
exynos_drm_gem_mmap_ioctl, DRM_UNLOCKED | DRM_AUTH),
|
||||
};
|
||||
|
||||
static struct drm_driver exynos_drm_driver = {
|
||||
.driver_features = DRIVER_HAVE_IRQ | DRIVER_BUS_PLATFORM |
|
||||
DRIVER_MODESET | DRIVER_GEM,
|
||||
.load = exynos_drm_load,
|
||||
.unload = exynos_drm_unload,
|
||||
.preclose = exynos_drm_preclose,
|
||||
.lastclose = exynos_drm_lastclose,
|
||||
.get_vblank_counter = drm_vblank_count,
|
||||
.enable_vblank = exynos_drm_crtc_enable_vblank,
|
||||
.disable_vblank = exynos_drm_crtc_disable_vblank,
|
||||
.gem_init_object = exynos_drm_gem_init_object,
|
||||
.gem_free_object = exynos_drm_gem_free_object,
|
||||
.gem_vm_ops = &exynos_drm_gem_vm_ops,
|
||||
.dumb_create = exynos_drm_gem_dumb_create,
|
||||
.dumb_map_offset = exynos_drm_gem_dumb_map_offset,
|
||||
.dumb_destroy = exynos_drm_gem_dumb_destroy,
|
||||
.ioctls = exynos_ioctls,
|
||||
.fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = drm_open,
|
||||
.mmap = exynos_drm_gem_mmap,
|
||||
.poll = drm_poll,
|
||||
.read = drm_read,
|
||||
.unlocked_ioctl = drm_ioctl,
|
||||
.release = drm_release,
|
||||
},
|
||||
.name = DRIVER_NAME,
|
||||
.desc = DRIVER_DESC,
|
||||
.date = DRIVER_DATE,
|
||||
.major = DRIVER_MAJOR,
|
||||
.minor = DRIVER_MINOR,
|
||||
};
|
||||
|
||||
static int exynos_drm_platform_probe(struct platform_device *pdev)
|
||||
{
|
||||
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
||||
|
||||
exynos_drm_driver.num_ioctls = DRM_ARRAY_SIZE(exynos_ioctls);
|
||||
|
||||
return drm_platform_init(&exynos_drm_driver, pdev);
|
||||
}
|
||||
|
||||
static int exynos_drm_platform_remove(struct platform_device *pdev)
|
||||
{
|
||||
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
||||
|
||||
drm_platform_exit(&exynos_drm_driver, pdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver exynos_drm_platform_driver = {
|
||||
.probe = exynos_drm_platform_probe,
|
||||
.remove = __devexit_p(exynos_drm_platform_remove),
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = DRIVER_NAME,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init exynos_drm_init(void)
|
||||
{
|
||||
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
||||
|
||||
return platform_driver_register(&exynos_drm_platform_driver);
|
||||
}
|
||||
|
||||
static void __exit exynos_drm_exit(void)
|
||||
{
|
||||
DRM_DEBUG_DRIVER("%s\n", __FILE__);
|
||||
|
||||
platform_driver_unregister(&exynos_drm_platform_driver);
|
||||
}
|
||||
|
||||
module_init(exynos_drm_init);
|
||||
module_exit(exynos_drm_exit);
|
||||
|
||||
MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
|
||||
MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
|
||||
MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>");
|
||||
MODULE_DESCRIPTION("Samsung SoC DRM Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -0,0 +1,254 @@
|
||||
/* exynos_drm_drv.h
|
||||
*
|
||||
* Copyright (c) 2011 Samsung Electronics Co., Ltd.
|
||||
* Authors:
|
||||
* Inki Dae <inki.dae@samsung.com>
|
||||
* Joonyoung Shim <jy0922.shim@samsung.com>
|
||||
* Seung-Woo Kim <sw0312.kim@samsung.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _EXYNOS_DRM_DRV_H_
|
||||
#define _EXYNOS_DRM_DRV_H_
|
||||
|
||||
#include "drm.h"
|
||||
|
||||
#define MAX_CRTC 2
|
||||
|
||||
struct drm_device;
|
||||
struct exynos_drm_overlay;
|
||||
struct drm_connector;
|
||||
|
||||
/* this enumerates display type. */
|
||||
enum exynos_drm_output_type {
|
||||
EXYNOS_DISPLAY_TYPE_NONE,
|
||||
/* RGB or CPU Interface. */
|
||||
EXYNOS_DISPLAY_TYPE_LCD,
|
||||
/* HDMI Interface. */
|
||||
EXYNOS_DISPLAY_TYPE_HDMI,
|
||||
};
|
||||
|
||||
/*
|
||||
* Exynos drm overlay ops structure.
|
||||
*
|
||||
* @mode_set: copy drm overlay info to hw specific overlay info.
|
||||
* @commit: apply hardware specific overlay data to registers.
|
||||
* @disable: disable hardware specific overlay.
|
||||
*/
|
||||
struct exynos_drm_overlay_ops {
|
||||
void (*mode_set)(struct device *subdrv_dev,
|
||||
struct exynos_drm_overlay *overlay);
|
||||
void (*commit)(struct device *subdrv_dev);
|
||||
void (*disable)(struct device *subdrv_dev);
|
||||
};
|
||||
|
||||
/*
|
||||
* Exynos drm common overlay structure.
|
||||
*
|
||||
* @fb_x: offset x on a framebuffer to be displayed.
|
||||
* - the unit is screen coordinates.
|
||||
* @fb_y: offset y on a framebuffer to be displayed.
|
||||
* - the unit is screen coordinates.
|
||||
* @fb_width: width of a framebuffer.
|
||||
* @fb_height: height of a framebuffer.
|
||||
* @crtc_x: offset x on hardware screen.
|
||||
* @crtc_y: offset y on hardware screen.
|
||||
* @crtc_width: window width to be displayed (hardware screen).
|
||||
* @crtc_height: window height to be displayed (hardware screen).
|
||||
* @mode_width: width of screen mode.
|
||||
* @mode_height: height of screen mode.
|
||||
* @refresh: refresh rate.
|
||||
* @scan_flag: interlace or progressive way.
|
||||
* (it could be DRM_MODE_FLAG_*)
|
||||
* @bpp: pixel size.(in bit)
|
||||
* @paddr: bus(accessed by dma) physical memory address to this overlay
|
||||
* and this is physically continuous.
|
||||
* @vaddr: virtual memory addresss to this overlay.
|
||||
* @default_win: a window to be enabled.
|
||||
* @color_key: color key on or off.
|
||||
* @index_color: if using color key feature then this value would be used
|
||||
* as index color.
|
||||
* @local_path: in case of lcd type, local path mode on or off.
|
||||
* @transparency: transparency on or off.
|
||||
* @activated: activated or not.
|
||||
*
|
||||
* this structure is common to exynos SoC and its contents would be copied
|
||||
* to hardware specific overlay info.
|
||||
*/
|
||||
struct exynos_drm_overlay {
|
||||
unsigned int fb_x;
|
||||
unsigned int fb_y;
|
||||
unsigned int fb_width;
|
||||
unsigned int fb_height;
|
||||
unsigned int crtc_x;
|
||||
unsigned int crtc_y;
|
||||
unsigned int crtc_width;
|
||||
unsigned int crtc_height;
|
||||
unsigned int mode_width;
|
||||
unsigned int mode_height;
|
||||
unsigned int refresh;
|
||||
unsigned int scan_flag;
|
||||
unsigned int bpp;
|
||||
unsigned int pitch;
|
||||
dma_addr_t paddr;
|
||||
void __iomem *vaddr;
|
||||
|
||||
bool default_win;
|
||||
bool color_key;
|
||||
unsigned int index_color;
|
||||
bool local_path;
|
||||
bool transparency;
|
||||
bool activated;
|
||||
};
|
||||
|
||||
/*
|
||||
* Exynos DRM Display Structure.
|
||||
* - this structure is common to analog tv, digital tv and lcd panel.
|
||||
*
|
||||
* @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI.
|
||||
* @is_connected: check for that display is connected or not.
|
||||
* @get_edid: get edid modes from display driver.
|
||||
* @get_timing: get timing object from display driver.
|
||||
* @check_timing: check if timing is valid or not.
|
||||
* @power_on: display device on or off.
|
||||
*/
|
||||
struct exynos_drm_display {
|
||||
enum exynos_drm_output_type type;
|
||||
bool (*is_connected)(struct device *dev);
|
||||
int (*get_edid)(struct device *dev, struct drm_connector *connector,
|
||||
u8 *edid, int len);
|
||||
void *(*get_timing)(struct device *dev);
|
||||
int (*check_timing)(struct device *dev, void *timing);
|
||||
int (*power_on)(struct device *dev, int mode);
|
||||
};
|
||||
|
||||
/*
|
||||
* Exynos drm manager ops
|
||||
*
|
||||
* @mode_set: convert drm_display_mode to hw specific display mode and
|
||||
* would be called by encoder->mode_set().
|
||||
* @commit: set current hw specific display mode to hw.
|
||||
* @enable_vblank: specific driver callback for enabling vblank interrupt.
|
||||
* @disable_vblank: specific driver callback for disabling vblank interrupt.
|
||||
*/
|
||||
struct exynos_drm_manager_ops {
|
||||
void (*mode_set)(struct device *subdrv_dev, void *mode);
|
||||
void (*commit)(struct device *subdrv_dev);
|
||||
int (*enable_vblank)(struct device *subdrv_dev);
|
||||
void (*disable_vblank)(struct device *subdrv_dev);
|
||||
};
|
||||
|
||||
/*
|
||||
* Exynos drm common manager structure.
|
||||
*
|
||||
* @dev: pointer to device object for subdrv device driver.
|
||||
* sub drivers such as display controller or hdmi driver,
|
||||
* have their own device object.
|
||||
* @ops: pointer to callbacks for exynos drm specific framebuffer.
|
||||
* these callbacks should be set by specific drivers such fimd
|
||||
* or hdmi driver and are used to control hardware global registers.
|
||||
* @overlay_ops: pointer to callbacks for exynos drm specific framebuffer.
|
||||
* these callbacks should be set by specific drivers such fimd
|
||||
* or hdmi driver and are used to control hardware overlay reigsters.
|
||||
* @display: pointer to callbacks for exynos drm specific framebuffer.
|
||||
* these callbacks should be set by specific drivers such fimd
|
||||
* or hdmi driver and are used to control display devices such as
|
||||
* analog tv, digital tv and lcd panel and also get timing data for them.
|
||||
*/
|
||||
struct exynos_drm_manager {
|
||||
struct device *dev;
|
||||
int pipe;
|
||||
struct exynos_drm_manager_ops *ops;
|
||||
struct exynos_drm_overlay_ops *overlay_ops;
|
||||
struct exynos_drm_display *display;
|
||||
};
|
||||
|
||||
/*
|
||||
* Exynos drm private structure.
|
||||
*/
|
||||
struct exynos_drm_private {
|
||||
struct drm_fb_helper *fb_helper;
|
||||
|
||||
/* list head for new event to be added. */
|
||||
struct list_head pageflip_event_list;
|
||||
|
||||
/*
|
||||
* created crtc object would be contained at this array and
|
||||
* this array is used to be aware of which crtc did it request vblank.
|
||||
*/
|
||||
struct drm_crtc *crtc[MAX_CRTC];
|
||||
};
|
||||
|
||||
/*
|
||||
* Exynos drm sub driver structure.
|
||||
*
|
||||
* @list: sub driver has its own list object to register to exynos drm driver.
|
||||
* @drm_dev: pointer to drm_device and this pointer would be set
|
||||
* when sub driver calls exynos_drm_subdrv_register().
|
||||
* @probe: this callback would be called by exynos drm driver after
|
||||
* subdrv is registered to it.
|
||||
* @remove: this callback is used to release resources created
|
||||
* by probe callback.
|
||||
* @manager: subdrv has its own manager to control a hardware appropriately
|
||||
* and we can access a hardware drawing on this manager.
|
||||
* @encoder: encoder object owned by this sub driver.
|
||||
* @connector: connector object owned by this sub driver.
|
||||
*/
|
||||
struct exynos_drm_subdrv {
|
||||
struct list_head list;
|
||||
struct drm_device *drm_dev;
|
||||
|
||||
int (*probe)(struct drm_device *drm_dev, struct device *dev);
|
||||
void (*remove)(struct drm_device *dev);
|
||||
|
||||
struct exynos_drm_manager manager;
|
||||
struct drm_encoder *encoder;
|
||||
struct drm_connector *connector;
|
||||
};
|
||||
|
||||
/*
|
||||
* this function calls a probe callback registered to sub driver list and
|
||||
* create its own encoder and connector and then set drm_device object
|
||||
* to global one.
|
||||
*/
|
||||
int exynos_drm_device_register(struct drm_device *dev);
|
||||
/*
|
||||
* this function calls a remove callback registered to sub driver list and
|
||||
* destroy its own encoder and connetor.
|
||||
*/
|
||||
int exynos_drm_device_unregister(struct drm_device *dev);
|
||||
|
||||
/*
|
||||
* this function would be called by sub drivers such as display controller
|
||||
* or hdmi driver to register this sub driver object to exynos drm driver
|
||||
* and when a sub driver is registered to exynos drm driver a probe callback
|
||||
* of the sub driver is called and creates its own encoder and connector
|
||||
* and then fb helper and drm mode group would be re-initialized.
|
||||
*/
|
||||
int exynos_drm_subdrv_register(struct exynos_drm_subdrv *drm_subdrv);
|
||||
|
||||
/*
|
||||
* this function removes subdrv list from exynos drm driver and fb helper
|
||||
* and drm mode group would be re-initialized.
|
||||
*/
|
||||
int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *drm_subdrv);
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user