Implement drivers for NVIDIA tegra124 display controller, HDMI source

and host1x module. Unfortunately, tegra124 SoC doesn't have 2D acceleration
engine and 3D requires not yet started nouveau driver.

These drivers forms a first non-x86 DRM2 enabled graphic stack.

Note, there are 2 outstanding issues:
 - The code uses gross hack in order to be comply with
   OBJT_MGTDEVICE pager. (See tegra_bo_init_pager() in tegra_bo.c)
 - Due to improper(probably) refcounting in drm_gem_mmap_single()
   (in drm_gem.c), the gem objects are never released.
I hope that I will be able to address both issues in finite time,
but I don't want to touch x86 world now.

MFC after: 1 month
This commit is contained in:
Michal Meloun 2016-12-26 14:36:05 +00:00
parent 02fe53a49f
commit a0a23564a3
15 changed files with 6819 additions and 14 deletions

View File

@ -123,11 +123,10 @@ device pci
device re # RealTek 8139C+/8169/8169S/8110S
# DRM2
#device fbd
#device vt
#device splash
#device kbdmux
#device drm2
device fbd
device vt
device kbdmux
device drm2
# Sound
#device sound

1229
sys/arm/nvidia/drm2/hdmi.c Normal file

File diff suppressed because it is too large Load Diff

335
sys/arm/nvidia/drm2/hdmi.h Normal file
View File

@ -0,0 +1,335 @@
/*
* Copyright (C) 2012 Avionic Design GmbH
*
* 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, sub license,
* 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 NON-INFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS 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.
*
* $FreeBSD$
*/
#ifndef _HDMI_H_
#define _HDMI_H_
enum hdmi_infoframe_type {
HDMI_INFOFRAME_TYPE_VENDOR = 0x81,
HDMI_INFOFRAME_TYPE_AVI = 0x82,
HDMI_INFOFRAME_TYPE_SPD = 0x83,
HDMI_INFOFRAME_TYPE_AUDIO = 0x84,
};
#define HDMI_IEEE_OUI 0x000c03
#define HDMI_INFOFRAME_HEADER_SIZE 4
#define HDMI_AVI_INFOFRAME_SIZE 13
#define HDMI_SPD_INFOFRAME_SIZE 25
#define HDMI_AUDIO_INFOFRAME_SIZE 10
#define HDMI_INFOFRAME_SIZE(type) \
(HDMI_INFOFRAME_HEADER_SIZE + HDMI_ ## type ## _INFOFRAME_SIZE)
struct hdmi_any_infoframe {
enum hdmi_infoframe_type type;
unsigned char version;
unsigned char length;
};
enum hdmi_colorspace {
HDMI_COLORSPACE_RGB,
HDMI_COLORSPACE_YUV422,
HDMI_COLORSPACE_YUV444,
HDMI_COLORSPACE_YUV420,
HDMI_COLORSPACE_RESERVED4,
HDMI_COLORSPACE_RESERVED5,
HDMI_COLORSPACE_RESERVED6,
HDMI_COLORSPACE_IDO_DEFINED,
};
enum hdmi_scan_mode {
HDMI_SCAN_MODE_NONE,
HDMI_SCAN_MODE_OVERSCAN,
HDMI_SCAN_MODE_UNDERSCAN,
HDMI_SCAN_MODE_RESERVED,
};
enum hdmi_colorimetry {
HDMI_COLORIMETRY_NONE,
HDMI_COLORIMETRY_ITU_601,
HDMI_COLORIMETRY_ITU_709,
HDMI_COLORIMETRY_EXTENDED,
};
enum hdmi_picture_aspect {
HDMI_PICTURE_ASPECT_NONE,
HDMI_PICTURE_ASPECT_4_3,
HDMI_PICTURE_ASPECT_16_9,
HDMI_PICTURE_ASPECT_RESERVED,
};
enum hdmi_active_aspect {
HDMI_ACTIVE_ASPECT_16_9_TOP = 2,
HDMI_ACTIVE_ASPECT_14_9_TOP = 3,
HDMI_ACTIVE_ASPECT_16_9_CENTER = 4,
HDMI_ACTIVE_ASPECT_PICTURE = 8,
HDMI_ACTIVE_ASPECT_4_3 = 9,
HDMI_ACTIVE_ASPECT_16_9 = 10,
HDMI_ACTIVE_ASPECT_14_9 = 11,
HDMI_ACTIVE_ASPECT_4_3_SP_14_9 = 13,
HDMI_ACTIVE_ASPECT_16_9_SP_14_9 = 14,
HDMI_ACTIVE_ASPECT_16_9_SP_4_3 = 15,
};
enum hdmi_extended_colorimetry {
HDMI_EXTENDED_COLORIMETRY_XV_YCC_601,
HDMI_EXTENDED_COLORIMETRY_XV_YCC_709,
HDMI_EXTENDED_COLORIMETRY_S_YCC_601,
HDMI_EXTENDED_COLORIMETRY_ADOBE_YCC_601,
HDMI_EXTENDED_COLORIMETRY_ADOBE_RGB,
/* The following EC values are only defined in CEA-861-F. */
HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM,
HDMI_EXTENDED_COLORIMETRY_BT2020,
HDMI_EXTENDED_COLORIMETRY_RESERVED,
};
enum hdmi_quantization_range {
HDMI_QUANTIZATION_RANGE_DEFAULT,
HDMI_QUANTIZATION_RANGE_LIMITED,
HDMI_QUANTIZATION_RANGE_FULL,
HDMI_QUANTIZATION_RANGE_RESERVED,
};
/* non-uniform picture scaling */
enum hdmi_nups {
HDMI_NUPS_UNKNOWN,
HDMI_NUPS_HORIZONTAL,
HDMI_NUPS_VERTICAL,
HDMI_NUPS_BOTH,
};
enum hdmi_ycc_quantization_range {
HDMI_YCC_QUANTIZATION_RANGE_LIMITED,
HDMI_YCC_QUANTIZATION_RANGE_FULL,
};
enum hdmi_content_type {
HDMI_CONTENT_TYPE_GRAPHICS,
HDMI_CONTENT_TYPE_PHOTO,
HDMI_CONTENT_TYPE_CINEMA,
HDMI_CONTENT_TYPE_GAME,
};
struct hdmi_avi_infoframe {
enum hdmi_infoframe_type type;
unsigned char version;
unsigned char length;
enum hdmi_colorspace colorspace;
enum hdmi_scan_mode scan_mode;
enum hdmi_colorimetry colorimetry;
enum hdmi_picture_aspect picture_aspect;
enum hdmi_active_aspect active_aspect;
bool itc;
enum hdmi_extended_colorimetry extended_colorimetry;
enum hdmi_quantization_range quantization_range;
enum hdmi_nups nups;
unsigned char video_code;
enum hdmi_ycc_quantization_range ycc_quantization_range;
enum hdmi_content_type content_type;
unsigned char pixel_repeat;
unsigned short top_bar;
unsigned short bottom_bar;
unsigned short left_bar;
unsigned short right_bar;
};
int hdmi_avi_infoframe_init(struct hdmi_avi_infoframe *frame);
ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
size_t size);
enum hdmi_spd_sdi {
HDMI_SPD_SDI_UNKNOWN,
HDMI_SPD_SDI_DSTB,
HDMI_SPD_SDI_DVDP,
HDMI_SPD_SDI_DVHS,
HDMI_SPD_SDI_HDDVR,
HDMI_SPD_SDI_DVC,
HDMI_SPD_SDI_DSC,
HDMI_SPD_SDI_VCD,
HDMI_SPD_SDI_GAME,
HDMI_SPD_SDI_PC,
HDMI_SPD_SDI_BD,
HDMI_SPD_SDI_SACD,
HDMI_SPD_SDI_HDDVD,
HDMI_SPD_SDI_PMP,
};
struct hdmi_spd_infoframe {
enum hdmi_infoframe_type type;
unsigned char version;
unsigned char length;
char vendor[8];
char product[16];
enum hdmi_spd_sdi sdi;
};
int hdmi_spd_infoframe_init(struct hdmi_spd_infoframe *frame,
const char *vendor, const char *product);
ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
size_t size);
enum hdmi_audio_coding_type {
HDMI_AUDIO_CODING_TYPE_STREAM,
HDMI_AUDIO_CODING_TYPE_PCM,
HDMI_AUDIO_CODING_TYPE_AC3,
HDMI_AUDIO_CODING_TYPE_MPEG1,
HDMI_AUDIO_CODING_TYPE_MP3,
HDMI_AUDIO_CODING_TYPE_MPEG2,
HDMI_AUDIO_CODING_TYPE_AAC_LC,
HDMI_AUDIO_CODING_TYPE_DTS,
HDMI_AUDIO_CODING_TYPE_ATRAC,
HDMI_AUDIO_CODING_TYPE_DSD,
HDMI_AUDIO_CODING_TYPE_EAC3,
HDMI_AUDIO_CODING_TYPE_DTS_HD,
HDMI_AUDIO_CODING_TYPE_MLP,
HDMI_AUDIO_CODING_TYPE_DST,
HDMI_AUDIO_CODING_TYPE_WMA_PRO,
HDMI_AUDIO_CODING_TYPE_CXT,
};
enum hdmi_audio_sample_size {
HDMI_AUDIO_SAMPLE_SIZE_STREAM,
HDMI_AUDIO_SAMPLE_SIZE_16,
HDMI_AUDIO_SAMPLE_SIZE_20,
HDMI_AUDIO_SAMPLE_SIZE_24,
};
enum hdmi_audio_sample_frequency {
HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM,
HDMI_AUDIO_SAMPLE_FREQUENCY_32000,
HDMI_AUDIO_SAMPLE_FREQUENCY_44100,
HDMI_AUDIO_SAMPLE_FREQUENCY_48000,
HDMI_AUDIO_SAMPLE_FREQUENCY_88200,
HDMI_AUDIO_SAMPLE_FREQUENCY_96000,
HDMI_AUDIO_SAMPLE_FREQUENCY_176400,
HDMI_AUDIO_SAMPLE_FREQUENCY_192000,
};
enum hdmi_audio_coding_type_ext {
/* Refer to Audio Coding Type (CT) field in Data Byte 1 */
HDMI_AUDIO_CODING_TYPE_EXT_CT,
/*
* The next three CXT values are defined in CEA-861-E only.
* They do not exist in older versions, and in CEA-861-F they are
* defined as 'Not in use'.
*/
HDMI_AUDIO_CODING_TYPE_EXT_HE_AAC,
HDMI_AUDIO_CODING_TYPE_EXT_HE_AAC_V2,
HDMI_AUDIO_CODING_TYPE_EXT_MPEG_SURROUND,
/* The following CXT values are only defined in CEA-861-F. */
HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_HE_AAC,
HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_HE_AAC_V2,
HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_AAC_LC,
HDMI_AUDIO_CODING_TYPE_EXT_DRA,
HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_HE_AAC_SURROUND,
HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_AAC_LC_SURROUND = 10,
};
struct hdmi_audio_infoframe {
enum hdmi_infoframe_type type;
unsigned char version;
unsigned char length;
unsigned char channels;
enum hdmi_audio_coding_type coding_type;
enum hdmi_audio_sample_size sample_size;
enum hdmi_audio_sample_frequency sample_frequency;
enum hdmi_audio_coding_type_ext coding_type_ext;
unsigned char channel_allocation;
unsigned char level_shift_value;
bool downmix_inhibit;
};
int hdmi_audio_infoframe_init(struct hdmi_audio_infoframe *frame);
ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
void *buffer, size_t size);
enum hdmi_3d_structure {
HDMI_3D_STRUCTURE_INVALID = -1,
HDMI_3D_STRUCTURE_FRAME_PACKING = 0,
HDMI_3D_STRUCTURE_FIELD_ALTERNATIVE,
HDMI_3D_STRUCTURE_LINE_ALTERNATIVE,
HDMI_3D_STRUCTURE_SIDE_BY_SIDE_FULL,
HDMI_3D_STRUCTURE_L_DEPTH,
HDMI_3D_STRUCTURE_L_DEPTH_GFX_GFX_DEPTH,
HDMI_3D_STRUCTURE_TOP_AND_BOTTOM,
HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF = 8,
};
struct hdmi_vendor_infoframe {
enum hdmi_infoframe_type type;
unsigned char version;
unsigned char length;
unsigned int oui;
uint8_t vic;
enum hdmi_3d_structure s3d_struct;
unsigned int s3d_ext_data;
};
int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame);
ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
void *buffer, size_t size);
union hdmi_vendor_any_infoframe {
struct {
enum hdmi_infoframe_type type;
unsigned char version;
unsigned char length;
unsigned int oui;
} any;
struct hdmi_vendor_infoframe hdmi;
};
/**
* union hdmi_infoframe - overall union of all abstract infoframe representations
* @any: generic infoframe
* @avi: avi infoframe
* @spd: spd infoframe
* @vendor: union of all vendor infoframes
* @audio: audio infoframe
*
* This is used by the generic pack function. This works since all infoframes
* have the same header which also indicates which type of infoframe should be
* packed.
*/
union hdmi_infoframe {
struct hdmi_any_infoframe any;
struct hdmi_avi_infoframe avi;
struct hdmi_spd_infoframe spd;
union hdmi_vendor_any_infoframe vendor;
struct hdmi_audio_infoframe audio;
};
ssize_t
hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size);
int hdmi_infoframe_unpack(union hdmi_infoframe *frame, void *buffer);
void hdmi_infoframe_log(union hdmi_infoframe *frame);
#endif /* _HDMI_H */

View File

@ -0,0 +1,369 @@
/*-
* Copyright (c) 2015 Michal Meloun
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <machine/bus.h>
#include <dev/extres/clk/clk.h>
#include <dev/drm2/drmP.h>
#include <dev/drm2/drm_crtc_helper.h>
#include <dev/drm2/drm_fb_helper.h>
#include <arm/nvidia/drm2/tegra_drm.h>
#include <sys/vmem.h>
#include <sys/vmem.h>
#include <vm/vm.h>
#include <vm/vm_pageout.h>
static void
tegra_bo_destruct(struct tegra_bo *bo)
{
vm_page_t m;
size_t size;
int i;
if (bo->cdev_pager == NULL)
return;
size = round_page(bo->gem_obj.size);
if (bo->vbase != 0)
pmap_qremove(bo->vbase, bo->npages);
VM_OBJECT_WLOCK(bo->cdev_pager);
for (i = 0; i < bo->npages; i++) {
m = bo->m[i];
cdev_pager_free_page(bo->cdev_pager, m);
vm_page_lock(m);
m->flags &= ~PG_FICTITIOUS;
vm_page_unwire(m, PQ_NONE);
vm_page_free(m);
vm_page_unlock(m);
}
VM_OBJECT_WUNLOCK(bo->cdev_pager);
vm_object_deallocate(bo->cdev_pager);
if (bo->vbase != 0)
vmem_free(kmem_arena, bo->vbase, size);
}
static void
tegra_bo_free_object(struct drm_gem_object *gem_obj)
{
struct tegra_bo *bo;
bo = container_of(gem_obj, struct tegra_bo, gem_obj);
drm_gem_free_mmap_offset(gem_obj);
drm_gem_object_release(gem_obj);
tegra_bo_destruct(bo);
free(bo->m, DRM_MEM_DRIVER);
free(bo, DRM_MEM_DRIVER);
}
static int
tegra_bo_alloc_contig(size_t npages, u_long alignment, vm_memattr_t memattr,
vm_page_t **ret_page)
{
vm_page_t m;
int pflags, tries, i;
vm_paddr_t low, high, boundary;
low = 0;
high = -1UL;
boundary = 0;
pflags = VM_ALLOC_NORMAL | VM_ALLOC_NOOBJ | VM_ALLOC_NOBUSY |
VM_ALLOC_WIRED | VM_ALLOC_ZERO;
tries = 0;
retry:
m = vm_page_alloc_contig(NULL, 0, pflags, npages, low, high, alignment,
boundary, memattr);
if (m == NULL) {
if (tries < 3) {
if (!vm_page_reclaim_contig(pflags, npages, low, high,
alignment, boundary))
VM_WAIT;
tries++;
goto retry;
}
return (ENOMEM);
}
for (i = 0; i < npages; i++, m++) {
if ((m->flags & PG_ZERO) == 0)
pmap_zero_page(m);
m->valid = VM_PAGE_BITS_ALL;
(*ret_page)[i] = m;
}
return (0);
}
/* Initialize pager and insert all object pages to it*/
static int
tegra_bo_init_pager(struct tegra_bo *bo)
{
vm_page_t m;
size_t size;
int i;
size = round_page(bo->gem_obj.size);
bo->pbase = VM_PAGE_TO_PHYS(bo->m[0]);
if (vmem_alloc(kmem_arena, size, M_WAITOK | M_BESTFIT, &bo->vbase))
return (ENOMEM);
VM_OBJECT_WLOCK(bo->cdev_pager);
for (i = 0; i < bo->npages; i++) {
m = bo->m[i];
/*
* XXX This is a temporary hack.
* We need pager suitable for paging (mmap) managed
* real (non-fictitious) pages.
* - managed pages are needed for clean module unload.
* - aliasing fictitious page to real one is bad,
* pmap cannot handle this situation without issues
* It expects that
* paddr = PHYS_TO_VM_PAGE(VM_PAGE_TO_PHYS(paddr))
* for every single page passed to pmap.
*/
m->oflags &= ~VPO_UNMANAGED;
m->flags |= PG_FICTITIOUS;
if (vm_page_insert(m, bo->cdev_pager, i) != 0)
return (EINVAL);
}
VM_OBJECT_WUNLOCK(bo->cdev_pager);
pmap_qenter(bo->vbase, bo->m, bo->npages);
return (0);
}
/* Allocate memory for frame buffer */
static int
tegra_bo_alloc(struct drm_device *drm, struct tegra_bo *bo)
{
size_t size;
int rv;
size = bo->gem_obj.size;
bo->npages = atop(size);
bo->m = malloc(sizeof(vm_page_t *) * bo->npages, DRM_MEM_DRIVER,
M_WAITOK | M_ZERO);
rv = tegra_bo_alloc_contig(bo->npages, PAGE_SIZE,
VM_MEMATTR_WRITE_COMBINING, &(bo->m));
if (rv != 0) {
DRM_WARNING("Cannot allocate memory for gem object.\n");
return (rv);
}
rv = tegra_bo_init_pager(bo);
if (rv != 0) {
DRM_WARNING("Cannot initialize gem object pager.\n");
return (rv);
}
return (0);
}
int
tegra_bo_create(struct drm_device *drm, size_t size, struct tegra_bo **res_bo)
{
struct tegra_bo *bo;
int rv;
if (size <= 0)
return (-EINVAL);
bo = malloc(sizeof(*bo), DRM_MEM_DRIVER, M_WAITOK | M_ZERO);
size = round_page(size);
rv = drm_gem_object_init(drm, &bo->gem_obj, size);
if (rv != 0) {
free(bo, DRM_MEM_DRIVER);
return (rv);
}
rv = drm_gem_create_mmap_offset(&bo->gem_obj);
if (rv != 0) {
drm_gem_object_release(&bo->gem_obj);
free(bo, DRM_MEM_DRIVER);
return (rv);
}
bo->cdev_pager = cdev_pager_allocate(&bo->gem_obj, OBJT_MGTDEVICE,
drm->driver->gem_pager_ops, size, 0, 0, NULL);
rv = tegra_bo_alloc(drm, bo);
if (rv != 0) {
tegra_bo_free_object(&bo->gem_obj);
return (rv);
}
*res_bo = bo;
return (0);
}
static int
tegra_bo_create_with_handle(struct drm_file *file, struct drm_device *drm,
size_t size, uint32_t *handle, struct tegra_bo **res_bo)
{
int rv;
struct tegra_bo *bo;
rv = tegra_bo_create(drm, size, &bo);
if (rv != 0)
return (rv);
rv = drm_gem_handle_create(file, &bo->gem_obj, handle);
if (rv != 0) {
tegra_bo_free_object(&bo->gem_obj);
drm_gem_object_release(&bo->gem_obj);
return (rv);
}
drm_gem_object_unreference_unlocked(&bo->gem_obj);
*res_bo = bo;
return (0);
}
static int
tegra_bo_dumb_create(struct drm_file *file, struct drm_device *drm_dev,
struct drm_mode_create_dumb *args)
{
struct tegra_drm *drm;
struct tegra_bo *bo;
int rv;
drm = container_of(drm_dev, struct tegra_drm, drm_dev);
args->pitch= (args->width * args->bpp + 7) / 8;
args->pitch = roundup(args->pitch, drm->pitch_align);
args->size = args->pitch * args->height;
rv = tegra_bo_create_with_handle(file, drm_dev, args->size,
&args->handle, &bo);
return (rv);
}
static int
tegra_bo_dumb_map_offset(struct drm_file *file_priv,
struct drm_device *drm_dev, uint32_t handle, uint64_t *offset)
{
struct drm_gem_object *gem_obj;
int rv;
DRM_LOCK(drm_dev);
gem_obj = drm_gem_object_lookup(drm_dev, file_priv, handle);
if (gem_obj == NULL) {
device_printf(drm_dev->dev, "Object not found\n");
DRM_UNLOCK(drm_dev);
return (-EINVAL);
}
rv = drm_gem_create_mmap_offset(gem_obj);
if (rv != 0)
goto fail;
*offset = DRM_GEM_MAPPING_OFF(gem_obj->map_list.key) |
DRM_GEM_MAPPING_KEY;
drm_gem_object_unreference(gem_obj);
DRM_UNLOCK(drm_dev);
return (0);
fail:
drm_gem_object_unreference(gem_obj);
DRM_UNLOCK(drm_dev);
return (rv);
}
static int
tegra_bo_dumb_destroy(struct drm_file *file_priv, struct drm_device *drm_dev,
unsigned int handle)
{
int rv;
rv = drm_gem_handle_delete(file_priv, handle);
return (rv);
}
/*
* mmap support
*/
static int
tegra_gem_pager_fault(vm_object_t vm_obj, vm_ooffset_t offset, int prot,
vm_page_t *mres)
{
#ifdef DRM_PAGER_DEBUG
DRM_DEBUG("object %p offset %jd prot %d mres %p\n",
vm_obj, (intmax_t)offset, prot, mres);
#endif
return (VM_PAGER_FAIL);
}
static int
tegra_gem_pager_ctor(void *handle, vm_ooffset_t size, vm_prot_t prot,
vm_ooffset_t foff, struct ucred *cred, u_short *color)
{
if (color != NULL)
*color = 0;
return (0);
}
static void
tegra_gem_pager_dtor(void *handle)
{
}
static struct cdev_pager_ops tegra_gem_pager_ops = {
.cdev_pg_fault = tegra_gem_pager_fault,
.cdev_pg_ctor = tegra_gem_pager_ctor,
.cdev_pg_dtor = tegra_gem_pager_dtor
};
/* Fill up relevant fields in drm_driver ops */
void
tegra_bo_driver_register(struct drm_driver *drm_drv)
{
drm_drv->gem_free_object = tegra_bo_free_object;
drm_drv->gem_pager_ops = &tegra_gem_pager_ops;
drm_drv->dumb_create = tegra_bo_dumb_create;
drm_drv->dumb_map_offset = tegra_bo_dumb_map_offset;
drm_drv->dumb_destroy = tegra_bo_dumb_destroy;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,57 @@
#-
# Copyright (c) 2015 Michal Meloun
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# $FreeBSD$
#
#include <machine/bus.h>
INTERFACE tegra_dc;
METHOD void write_4{
device_t dev;
bus_size_t offset;
uint32_t val;
};
METHOD uint32_t read_4{
device_t dev;
bus_size_t offset;
};
METHOD void display_enable{
device_t dev;
bool enable;
};
METHOD void hdmi_enable{
device_t dev;
bool enable;
};
METHOD void setup_timing{
device_t dev;
int h_pulse_start;
};

View File

@ -0,0 +1,400 @@
/*-
* Copyright 1992-2015 Michal Meloun
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef _TEGRA_DC_REG_H_
#define _TEGRA_DC_REG_H_
/*
* !!! WARNING !!!
* Tegra manual uses registers index (and not register addreses).
* We follow the TRM notation and index is converted to offset in
* WR4 / RD4 macros
*/
/* --------------------------- DC CMD -------------------------------------- */
#define DC_CMD_GENERAL_INCR_SYNCPT 0x000
#define DC_CMD_GENERAL_INCR_SYNCPT_CNTRL 0x001
#define SYNCPT_CNTRL_NO_STALL (1 << 8)
#define SYNCPT_CNTRL_SOFT_RESET (1 << 0)
#define DC_CMD_GENERAL_INCR_SYNCPT_ERROR 0x002
#define DC_CMD_WIN_A_INCR_SYNCPT 0x008
#define DC_CMD_WIN_A_INCR_SYNCPT_CNTRL 0x009
#define DC_CMD_WIN_A_INCR_SYNCPT_ERROR 0x00a
#define DC_CMD_WIN_B_INCR_SYNCPT 0x010
#define DC_CMD_WIN_B_INCR_SYNCPT_CNTRL 0x011
#define DC_CMD_WIN_B_INCR_SYNCPT_ERROR 0x012
#define DC_CMD_WIN_C_INCR_SYNCPT 0x018
#define DC_CMD_WIN_C_INCR_SYNCPT_CNTRL 0x019
#define DC_CMD_WIN_C_INCR_SYNCPT_ERROR 0x01a
#define DC_CMD_CONT_SYNCPT_VSYNC 0x028
#define SYNCPT_VSYNC_ENABLE (1 << 8)
#define DC_CMD_CTXSW 0x030
#define DC_CMD_DISPLAY_COMMAND_OPTION0 0x031
#define DC_CMD_DISPLAY_COMMAND 0x032
#define DISPLAY_CTRL_MODE(x) ((x) << 5)
#define CTRL_MODE_STOP 0
#define CTRL_MODE_C_DISPLAY 1
#define CTRL_MODE_NC_DISPLAY 2
#define DC_CMD_SIGNAL_RAISE 0x033
#define DC_CMD_DISPLAY_POWER_CONTROL 0x036
#define PM1_ENABLE (1 << 18)
#define PM0_ENABLE (1 << 16)
#define PW4_ENABLE (1 << 8)
#define PW3_ENABLE (1 << 6)
#define PW2_ENABLE (1 << 4)
#define PW1_ENABLE (1 << 2)
#define PW0_ENABLE (1 << 0)
#define DC_CMD_INT_STATUS 0x037
#define DC_CMD_INT_MASK 0x038
#define DC_CMD_INT_ENABLE 0x039
#define DC_CMD_INT_TYPE 0x03a
#define DC_CMD_INT_POLARITY 0x03b
#define WIN_T_UF_INT (1 << 25)
#define WIN_D_UF_INT (1 << 24)
#define HC_UF_INT (1 << 23)
#define CMU_LUT_CONFLICT_INT (1 << 22)
#define WIN_C_OF_INT (1 << 16)
#define WIN_B_OF_INT (1 << 15)
#define WIN_A_OF_INT (1 << 14)
#define SSF_INT (1 << 13)
#define MSF_INT (1 << 12)
#define WIN_C_UF_INT (1 << 10)
#define WIN_B_UF_INT (1 << 9)
#define WIN_A_UF_INT (1 << 8)
#define SPI_BUSY_INT (1 << 6)
#define V_PULSE2_INT (1 << 5)
#define V_PULSE3_INT (1 << 4)
#define HBLANK_INT (1 << 3)
#define VBLANK_INT (1 << 2)
#define FRAME_END_INT (1 << 1)
#define DC_CMD_STATE_ACCESS 0x040
#define WRITE_MUX (1 << 2)
#define READ_MUX (1 << 0)
#define DC_CMD_STATE_CONTROL 0x041
#define NC_HOST_TRIG (1 << 24)
#define CURSOR_UPDATE (1 << 15)
#define WIN_C_UPDATE (1 << 11)
#define WIN_B_UPDATE (1 << 10)
#define WIN_A_UPDATE (1 << 9)
#define WIN_UPDATE(x) (1 << (9 + (x)))
#define GENERAL_UPDATE (1 << 8)
#define CURSOR_ACT_REQ (1 << 7)
#define WIN_D_ACT_REQ (1 << 4)
#define WIN_C_ACT_REQ (1 << 3)
#define WIN_B_ACT_REQ (1 << 2)
#define WIN_A_ACT_REQ (1 << 1)
#define WIN_ACT_REQ(x) (1 << (1 + (x)))
#define GENERAL_ACT_REQ (1 << 0)
#define DC_CMD_DISPLAY_WINDOW_HEADER 0x042
#define WINDOW_D_SELECT (1 << 7)
#define WINDOW_C_SELECT (1 << 6)
#define WINDOW_B_SELECT (1 << 5)
#define WINDOW_A_SELECT (1 << 4)
#define WINDOW_SELECT(x) (1 << (4 + (x)))
#define DC_CMD_REG_ACT_CONTROL 0x043
#define DC_CMD_WIN_D_INCR_SYNCPT 0x04c
#define DC_CMD_WIN_D_INCR_SYNCPT_CNTRL 0x04d
#define DC_CMD_WIN_D_INCR_SYNCPT_ERROR 0x04e
/* ---------------------------- DC COM ------------------------------------- */
/* --------------------------- DC DISP ------------------------------------- */
#define DC_DISP_DISP_SIGNAL_OPTIONS0 0x400
#define M1_ENABLE (1 << 26)
#define M0_ENABLE (1 << 24)
#define V_PULSE2_ENABLE (1 << 18)
#define V_PULSE1_ENABLE (1 << 16)
#define V_PULSE0_ENABLE (1 << 14)
#define H_PULSE2_ENABLE (1 << 12)
#define H_PULSE1_ENABLE (1 << 10)
#define H_PULSE0_ENABLE (1 << 8)
#define DC_DISP_DISP_SIGNAL_OPTIONS1 0x401
#define DC_DISP_DISP_WIN_OPTIONS 0x402
#define HDMI_ENABLE (1 << 30)
#define DSI_ENABLE (1 << 29)
#define SOR1_TIMING_CYA (1 << 27)
#define SOR1_ENABLE (1 << 26)
#define SOR_ENABLE (1 << 25)
#define CURSOR_ENABLE (1 << 16)
#define DC_DISP_DISP_TIMING_OPTIONS 0x405
#define VSYNC_H_POSITION(x) (((x) & 0xfff) << 0)
#define DC_DISP_REF_TO_SYNC 0x406
#define DC_DISP_SYNC_WIDTH 0x407
#define DC_DISP_BACK_PORCH 0x408
#define DC_DISP_DISP_ACTIVE 0x409
#define DC_DISP_FRONT_PORCH 0x40a
#define DC_DISP_H_PULSE0_CONTROL 0x40b
#define DC_DISP_H_PULSE0_POSITION_A 0x40c
#define DC_DISP_H_PULSE0_POSITION_B 0x40d
#define DC_DISP_H_PULSE0_POSITION_C 0x40e
#define DC_DISP_H_PULSE0_POSITION_D 0x40f
#define DC_DISP_H_PULSE1_CONTROL 0x410
#define DC_DISP_H_PULSE1_POSITION_A 0x411
#define DC_DISP_H_PULSE1_POSITION_B 0x412
#define DC_DISP_H_PULSE1_POSITION_C 0x413
#define DC_DISP_H_PULSE1_POSITION_D 0x414
#define DC_DISP_H_PULSE2_CONTROL 0x415
#define DC_DISP_H_PULSE2_POSITION_A 0x416
#define DC_DISP_H_PULSE2_POSITION_B 0x417
#define DC_DISP_H_PULSE2_POSITION_C 0x418
#define DC_DISP_H_PULSE2_POSITION_D 0x419
#define DC_DISP_V_PULSE0_CONTROL 0x41a
#define DC_DISP_V_PULSE0_POSITION_A 0x41b
#define DC_DISP_V_PULSE0_POSITION_B 0x41c
#define DC_DISP_V_PULSE0_POSITION_C 0x41d
#define DC_DISP_V_PULSE1_CONTROL 0x41e
#define DC_DISP_V_PULSE1_POSITION_A 0x41f
#define DC_DISP_V_PULSE1_POSITION_B 0x420
#define DC_DISP_V_PULSE1_POSITION_C 0x421
#define DC_DISP_V_PULSE2_CONTROL 0x422
#define DC_DISP_V_PULSE2_POSITION_A 0x423
#define DC_DISP_V_PULSE3_CONTROL 0x424
#define PULSE_CONTROL_LAST(x) (((x) & 0x7f) << 8)
#define LAST_START_A 0
#define LAST_END_A 1
#define LAST_START_B 2
#define LAST_END_B 3
#define LAST_START_C 4
#define LAST_END_C 5
#define LAST_START_D 6
#define LAST_END_D 7
#define PULSE_CONTROL_QUAL(x) (((x) & 0x3) << 8)
#define QUAL_ALWAYS 0
#define QUAL_VACTIVE 2
#define QUAL_VACTIVE1 3
#define PULSE_POLARITY (1 << 4)
#define PULSE_MODE (1 << 3)
#define DC_DISP_V_PULSE3_POSITION_A 0x425
#define PULSE_END(x) (((x) & 0xfff) << 16)
#define PULSE_START(x) (((x) & 0xfff) << 0)
#define DC_DISP_DISP_CLOCK_CONTROL 0x42e
#define PIXEL_CLK_DIVIDER(x) (((x) & 0xf) << 8)
#define PCD1 0
#define PCD1H 1
#define PCD2 2
#define PCD3 3
#define PCD4 4
#define PCD6 5
#define PCD8 6
#define PCD9 7
#define PCD12 8
#define PCD16 9
#define PCD18 10
#define PCD24 11
#define PCD13 12
#define SHIFT_CLK_DIVIDER(x) ((x) & 0xff)
#define DC_DISP_DISP_INTERFACE_CONTROL 0x42f
#define DISP_ORDER_BLUE_RED ( 1 << 9)
#define DISP_ALIGNMENT_LSB ( 1 << 8)
#define DISP_DATA_FORMAT(x) (((x) & 0xf) << 8)
#define DF1P1C 0
#define DF1P2C24B 1
#define DF1P2C18B 2
#define DF1P2C16B 3
#define DF1S 4
#define DF2S 5
#define DF3S 6
#define DFSPI 7
#define DF1P3C24B 8
#define DF2P1C18B 9
#define DFDUAL1P1C18B 10
#define DC_DISP_DISP_COLOR_CONTROL 0x430
#define NON_BASE_COLOR (1 << 18)
#define BLANK_COLOR (1 << 17)
#define DISP_COLOR_SWAP (1 << 16)
#define ORD_DITHER_ROTATION(x) (((x) & 0x3) << 12)
#define DITHER_CONTROL(x) (((x) & 0x3) << 8)
#define DITHER_DISABLE 0
#define DITHER_ORDERED 2
#define DITHER_TEMPORAL 3
#define BASE_COLOR_SIZE(x) (((x) & 0xF) << 0)
#define SIZE_BASE666 0
#define SIZE_BASE111 1
#define SIZE_BASE222 2
#define SIZE_BASE333 3
#define SIZE_BASE444 4
#define SIZE_BASE555 5
#define SIZE_BASE565 6
#define SIZE_BASE332 7
#define SIZE_BASE888 8
#define DC_DISP_CURSOR_START_ADDR 0x43e
#define CURSOR_CLIP(x) (((x) & 0x3) << 28)
#define CC_DISPLAY 0
#define CC_WA 1
#define CC_WB 2
#define CC_WC 3
#define CURSOR_SIZE(x) (((x) & 0x3) << 24)
#define C32x32 0
#define C64x64 1
#define C128x128 2
#define C256x256 3
#define CURSOR_START_ADDR(x) (((x) >> 10) & 0x3FFFFF)
#define DC_DISP_CURSOR_POSITION 0x440
#define CURSOR_POSITION(h, v) ((((h) & 0x3fff) << 0) | \
(((v) & 0x3fff) << 16))
#define DC_DISP_CURSOR_UNDERFLOW_CTRL 0x4eb
#define DC_DISP_BLEND_CURSOR_CONTROL 0x4f1
#define CURSOR_MODE_SELECT (1 << 24)
#define CURSOR_DST_BLEND_FACTOR_SELECT(x) (((x) & 0x3) << 16)
#define DST_BLEND_ZERO 0
#define DST_BLEND_K1 1
#define DST_NEG_K1_TIMES_SRC 2
#define CURSOR_SRC_BLEND_FACTOR_SELECT(x) (((x) & 0x3) << 8)
#define SRC_BLEND_K1 0
#define SRC_BLEND_K1_TIMES_SRC 1
#define CURSOR_ALPHA(x) (((x) & 0xFF) << 0)
#define DC_DISP_CURSOR_UFLOW_DBG_PIXEL 0x4f3
#define CURSOR_UFLOW_CYA (1 << 7)
#define CURSOR_UFLOW_CTRL_DBG_MODE (1 << 0)
/* --------------------------- DC WIN ------------------------------------- */
#define DC_WINC_COLOR_PALETTE 0x500
#define DC_WINC_CSC_YOF 0x611
#define DC_WINC_CSC_KYRGB 0x612
#define DC_WINC_CSC_KUR 0x613
#define DC_WINC_CSC_KVR 0x614
#define DC_WINC_CSC_KUG 0x615
#define DC_WINC_CSC_KVG 0x616
#define DC_WINC_CSC_KUB 0x617
#define DC_WINC_CSC_KVB 0x618
#define DC_WINC_WIN_OPTIONS 0x700
#define H_FILTER_MODE (1U << 31)
#define WIN_ENABLE (1 << 30)
#define INTERLACE_ENABLE (1 << 23)
#define YUV_RANGE_EXPAND (1 << 22)
#define DV_ENABLE (1 << 20)
#define CSC_ENABLE (1 << 18)
#define CP_ENABLE (1 << 16)
#define V_FILTER_UV_ALIGN (1 << 14)
#define V_FILTER_OPTIMIZE (1 << 12)
#define V_FILTER_ENABLE (1 << 10)
#define H_FILTER_ENABLE (1 << 8)
#define COLOR_EXPAND (1 << 6)
#define SCAN_COLUMN (1 << 4)
#define V_DIRECTION (1 << 2)
#define H_DIRECTION (1 << 0)
#define DC_WIN_BYTE_SWAP 0x701
#define BYTE_SWAP(x) (((x) & 0x7) << 0)
#define NOSWAP 0
#define SWAP2 1
#define SWAP4 2
#define SWAP4HW 3
#define SWAP02 4
#define SWAPLEFT 5
#define DC_WIN_COLOR_DEPTH 0x703
#define WIN_COLOR_DEPTH_P8 3
#define WIN_COLOR_DEPTH_B4G4R4A4 4
#define WIN_COLOR_DEPTH_B5G5R5A 5
#define WIN_COLOR_DEPTH_B5G6R5 6
#define WIN_COLOR_DEPTH_AB5G5R5 7
#define WIN_COLOR_DEPTH_B8G8R8A8 12
#define WIN_COLOR_DEPTH_R8G8B8A8 13
#define WIN_COLOR_DEPTH_YCbCr422 16
#define WIN_COLOR_DEPTH_YUV422 17
#define WIN_COLOR_DEPTH_YCbCr420P 18
#define WIN_COLOR_DEPTH_YUV420P 19
#define WIN_COLOR_DEPTH_YCbCr422P 20
#define WIN_COLOR_DEPTH_YUV422P 21
#define WIN_COLOR_DEPTH_YCbCr422R 22
#define WIN_COLOR_DEPTH_YUV422R 23
#define WIN_COLOR_DEPTH_YCbCr422RA 24
#define WIN_COLOR_DEPTH_YUV422RA 25
#define DC_WIN_POSITION 0x704
#define WIN_POSITION(h, v) ((((h) & 0x1fff) << 0) | \
(((v) & 0x1fff) << 16))
#define DC_WIN_SIZE 0x705
#define WIN_SIZE(h, v) ((((h) & 0x1fff) << 0) | \
(((v) & 0x1fff) << 16))
#define DC_WIN_PRESCALED_SIZE 0x706
#define WIN_PRESCALED_SIZE(h, v) ((((h) & 0x7fff) << 0) | \
(((v) & 0x1fff) << 16))
#define DC_WIN_H_INITIAL_DDA 0x707
#define DC_WIN_V_INITIAL_DDA 0x708
#define DC_WIN_DDA_INCREMENT 0x709
#define WIN_DDA_INCREMENT(h, v) ((((h) & 0xffff) << 0) | \
(((v) & 0xffff) << 16))
#define DC_WIN_LINE_STRIDE 0x70a
/* -------------------------- DC WINBUF ------------------------------------ */
#define DC_WINBUF_START_ADDR 0x800
#define DC_WINBUF_START_ADDR_NS 0x801
#define DC_WINBUF_START_ADDR_U 0x802
#define DC_WINBUF_START_ADDR_U_NS 0x803
#define DC_WINBUF_START_ADDR_V 0x804
#define DC_WINBUF_START_ADDR_V_NS 0x805
#define DC_WINBUF_ADDR_H_OFFSET 0x806
#define DC_WINBUF_ADDR_H_OFFSET_NS 0x807
#define DC_WINBUF_ADDR_V_OFFSET 0x808
#define DC_WINBUF_ADDR_V_OFFSET_NS 0x809
#define DC_WINBUF_UFLOW_STATUS 0x80a
#define DC_WINBUF_SURFACE_KIND 0x80b
#define SURFACE_KIND_BLOCK_HEIGHT(x) (((x) & 0x7) << 4)
#define SURFACE_KIND_PITCH 0
#define SURFACE_KIND_TILED 1
#define SURFACE_KIND_BL_16B2 2
#define DC_WINBUF_SURFACE_WEIGHT 0x80c
#define DC_WINBUF_START_ADDR_HI 0x80d
#define DC_WINBUF_START_ADDR_HI_NS 0x80e
#define DC_WINBUF_START_ADDR_U_HI 0x80f
#define DC_WINBUF_START_ADDR_U_HI_NS 0x810
#define DC_WINBUF_START_ADDR_V_HI 0x811
#define DC_WINBUF_START_ADDR_V_HI_NS 0x812
#define DC_WINBUF_UFLOW_CTRL 0x824
#define UFLOW_CTR_ENABLE (1 << 0)
#define DC_WINBUF_UFLOW_DBG_PIXEL 0x825
#endif /* _TEGRA_DC_REG_H_ */

View File

@ -0,0 +1,125 @@
/*-
* Copyright 1992-2015 Michal Meloun
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef _TEGRA_DRM_H_
#define _TEGRA_DRM_H_
#include <dev/gpio/gpiobusvar.h>
struct tegra_bo {
struct drm_gem_object gem_obj;
/* mapped memory buffer */
vm_paddr_t pbase;
vm_offset_t vbase;
size_t npages;
vm_page_t *m;
vm_object_t cdev_pager;
};
struct tegra_plane {
struct drm_plane drm_plane;
int index; /* Window index */
};
struct tegra_fb {
struct drm_framebuffer drm_fb;
struct drm_fb_helper fb_helper;
struct tegra_bo **planes; /* Attached planes */
int nplanes;
/* Surface and display geometry */
bool block_linear; /* Surface_kind */
uint32_t block_height;
int rotation; /* In degrees */
bool flip_x; /* Inverted X-axis */
bool flip_y; /* Inverted Y-axis */
};
struct tegra_crtc {
struct drm_crtc drm_crtc;
device_t dev;
int nvidia_head;
vm_paddr_t cursor_pbase; /* Cursor buffer */
vm_offset_t cursor_vbase;
};
struct tegra_drm_encoder {
device_t dev;
void *panel; /* XXX For LVDS panel */
device_t ddc;
struct edid *edid;
gpio_pin_t gpio_hpd;
struct drm_encoder encoder;
struct drm_connector connector;
int (*setup_clock)(struct tegra_drm_encoder *output,
clk_t clk, uint64_t pclk);
};
struct tegra_drm {
struct drm_device drm_dev;
struct tegra_fb *fb; /* Prime framebuffer */
int pitch_align;
};
/* tegra_drm_subr.c */
int tegra_drm_encoder_attach(struct tegra_drm_encoder *output, phandle_t node);
int tegra_drm_encoder_init(struct tegra_drm_encoder *output,
struct tegra_drm *drm);
int tegra_drm_encoder_exit(struct tegra_drm_encoder *output,
struct tegra_drm *drm);
enum drm_connector_status tegra_drm_connector_detect(
struct drm_connector *connector, bool force);
int tegra_drm_connector_get_modes(struct drm_connector *connector);
struct drm_encoder *tegra_drm_connector_best_encoder(
struct drm_connector *connector);
/* tegra_dc.c */
void tegra_dc_cancel_page_flip(struct drm_crtc *drm_crtc,
struct drm_file *file);
void tegra_dc_enable_vblank(struct drm_crtc *drm_crtc);
void tegra_dc_disable_vblank(struct drm_crtc *drm_crtc);
int tegra_dc_get_pipe(struct drm_crtc *drm_crtc);
/* tegra_fb.c */
struct fb_info *tegra_drm_fb_getinfo(struct drm_device *drm);
struct tegra_bo *tegra_fb_get_plane(struct tegra_fb *fb, int idx);
int tegra_drm_fb_create(struct drm_device *drm, struct drm_file *file,
struct drm_mode_fb_cmd2 *cmd, struct drm_framebuffer **fb_res);
int tegra_drm_fb_init(struct drm_device *drm);
void tegra_drm_fb_destroy(struct drm_device *drm);
/* tegra_bo.c */
struct tegra_bo;
int tegra_bo_create(struct drm_device *drm, size_t size,
struct tegra_bo **res_bo);
void tegra_bo_driver_register(struct drm_driver *drm_drv);
#endif /* _TEGRA_DRM_H_ */

View File

@ -0,0 +1,68 @@
#-
# Copyright (c) 2015 Michal Meloun
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# $FreeBSD$
#
INTERFACE tegra_drm;
HEADER {
struct tegra_drm;
};
/**
* Register client to host1x
*/
METHOD int register_client{
device_t host1x;
device_t client;
};
/**
* Deregister client to host1x
*/
METHOD int deregister_client{
device_t host1x;
device_t client;
};
/**
* Call client init method
*/
METHOD int init_client{
device_t client;
device_t host1x;
struct tegra_drm *drm;
};
/**
* Call client exit method
*/
METHOD int exit_client{
device_t client;
device_t host1x;
struct tegra_drm *drm;
};

View File

@ -0,0 +1,177 @@
/*-
* Copyright (c) 2015 Michal Meloun
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <machine/bus.h>
#include <dev/extres/clk/clk.h>
#include <dev/drm2/drmP.h>
#include <dev/drm2/drm_crtc.h>
#include <dev/drm2/drm_crtc_helper.h>
#include <dev/drm2/drm_edid.h>
#include <dev/drm2/drm_fb_helper.h>
#include <dev/gpio/gpiobusvar.h>
#include <dev/ofw/ofw_bus_subr.h>
#include <arm/nvidia/drm2/tegra_drm.h>
#include <gnu/dts/include/dt-bindings/gpio/gpio.h>
int
tegra_drm_connector_get_modes(struct drm_connector *connector)
{
struct tegra_drm_encoder *output;
struct edid *edid = NULL;
int rv;
output = container_of(connector, struct tegra_drm_encoder,
connector);
/* Panel is first */
if (output->panel != NULL) {
/* XXX panel parsing */
return (0);
}
/* static EDID is second*/
edid = output->edid;
/* EDID from monitor is last */
if (edid == NULL)
edid = drm_get_edid(connector, output->ddc);
if (edid == NULL)
return (0);
/* Process EDID */
drm_mode_connector_update_edid_property(connector, edid);
rv = drm_add_edid_modes(connector, edid);
drm_edid_to_eld(connector, edid);
return (rv);
}
struct drm_encoder *
tegra_drm_connector_best_encoder(struct drm_connector *connector)
{
struct tegra_drm_encoder *output;
output = container_of(connector, struct tegra_drm_encoder,
connector);
return &(output->encoder);
}
enum drm_connector_status
tegra_drm_connector_detect(struct drm_connector *connector, bool force)
{
struct tegra_drm_encoder *output;
bool active;
int rv;
output = container_of(connector, struct tegra_drm_encoder,
connector);
if (output->gpio_hpd == NULL) {
return ((output->panel != NULL) ?
connector_status_connected:
connector_status_disconnected);
}
rv = gpio_pin_is_active(output->gpio_hpd, &active);
if (rv != 0) {
device_printf(output->dev, " GPIO read failed: %d\n", rv);
return (connector_status_unknown);
}
return (active ?
connector_status_connected : connector_status_disconnected);
}
int
tegra_drm_encoder_attach(struct tegra_drm_encoder *output, phandle_t node)
{
int rv;
phandle_t ddc;
/* XXX parse output panel here */
rv = OF_getencprop_alloc(node, "nvidia,edid", 1,
(void **)&output->edid);
/* EDID exist but have invalid size */
if ((rv >= 0) && (rv != sizeof(struct edid))) {
device_printf(output->dev,
"Malformed \"nvidia,edid\" property\n");
if (output->edid != NULL)
free(output->edid, M_OFWPROP);
return (ENXIO);
}
gpio_pin_get_by_ofw_property(output->dev, node, "nvidia,hpd-gpio",
&output->gpio_hpd);
ddc = 0;
OF_getencprop(node, "nvidia,ddc-i2c-bus", &ddc, sizeof(ddc));
if (ddc > 0)
output->ddc = OF_device_from_xref(ddc);
if ((output->edid == NULL) && (output->ddc == NULL))
return (ENXIO);
if (output->gpio_hpd != NULL) {
output->connector.polled =
// DRM_CONNECTOR_POLL_HPD;
DRM_CONNECTOR_POLL_DISCONNECT |
DRM_CONNECTOR_POLL_CONNECT;
}
return (0);
}
int tegra_drm_encoder_init(struct tegra_drm_encoder *output,
struct tegra_drm *drm)
{
if (output->panel) {
/* attach panel */
}
return (0);
}
int tegra_drm_encoder_exit(struct tegra_drm_encoder *output,
struct tegra_drm *drm)
{
if (output->panel) {
/* detach panel */
}
return (0);
}

View File

@ -0,0 +1,338 @@
/*-
* Copyright (c) 2016 Michal Meloun
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <machine/bus.h>
#include <dev/extres/clk/clk.h>
#include <dev/drm2/drmP.h>
#include <dev/drm2/drm_crtc_helper.h>
#include <dev/drm2/drm_fb_helper.h>
#include <arm/nvidia/drm2/tegra_drm.h>
static void
fb_destroy(struct drm_framebuffer *drm_fb)
{
struct tegra_fb *fb;
struct tegra_bo *bo;
unsigned int i;
fb = container_of(drm_fb, struct tegra_fb, drm_fb);
for (i = 0; i < fb->nplanes; i++) {
bo = fb->planes[i];
if (bo != NULL)
drm_gem_object_unreference_unlocked(&bo->gem_obj);
}
drm_framebuffer_cleanup(drm_fb);
free(fb->planes, DRM_MEM_DRIVER);
}
static int
fb_create_handle(struct drm_framebuffer *drm_fb, struct drm_file *file,
unsigned int *handle)
{
struct tegra_fb *fb;
int rv;
fb = container_of(drm_fb, struct tegra_fb, drm_fb);
rv = drm_gem_handle_create(file, &fb->planes[0]->gem_obj, handle);
return (rv);
}
/* XXX Probably not needed */
static int
fb_dirty(struct drm_framebuffer *fb, struct drm_file *file_priv,
unsigned flags, unsigned color, struct drm_clip_rect *clips, unsigned num_clips)
{
return (0);
}
static const struct drm_framebuffer_funcs fb_funcs = {
.destroy = fb_destroy,
.create_handle = fb_create_handle,
.dirty = fb_dirty,
};
static int
fb_alloc(struct drm_device *drm, struct drm_mode_fb_cmd2 *mode_cmd,
struct tegra_bo **planes, int num_planes, struct tegra_fb **res_fb)
{
struct tegra_fb *fb;
int i;
int rv;
fb = malloc(sizeof(*fb), DRM_MEM_DRIVER, M_WAITOK | M_ZERO);
fb->planes = malloc(num_planes * sizeof(*fb->planes), DRM_MEM_DRIVER,
M_WAITOK | M_ZERO);
fb->nplanes = num_planes;
drm_helper_mode_fill_fb_struct(&fb->drm_fb, mode_cmd);
for (i = 0; i < fb->nplanes; i++)
fb->planes[i] = planes[i];
rv = drm_framebuffer_init(drm, &fb->drm_fb, &fb_funcs);
if (rv < 0) {
device_printf(drm->dev,
"Cannot initialize frame buffer %d\n", rv);
free(fb->planes, DRM_MEM_DRIVER);
return (rv);
}
*res_fb = fb;
return (0);
}
static int
tegra_fb_probe(struct drm_fb_helper *helper,
struct drm_fb_helper_surface_size *sizes)
{
u_int bpp, size;
struct tegra_drm *drm;
struct tegra_fb *fb;
struct fb_info *info;
struct tegra_bo *bo;
struct drm_mode_fb_cmd2 mode_cmd;
struct drm_device *drm_dev;
int rv;
if (helper->fb != NULL)
return (0);
DRM_DEBUG_KMS("surface: %d x %d (bpp: %d)\n", sizes->surface_width,
sizes->surface_height, sizes->surface_bpp);
drm_dev = helper->dev;
fb = container_of(helper, struct tegra_fb, fb_helper);
drm = container_of(drm_dev, struct tegra_drm, drm_dev);
bpp = (sizes->surface_bpp + 7) / 8;
/* Create mode_cmd */
memset(&mode_cmd, 0, sizeof(mode_cmd));
mode_cmd.width = sizes->surface_width;
mode_cmd.height = sizes->surface_height;
mode_cmd.pitches[0] = roundup(sizes->surface_width * bpp,
drm->pitch_align);
mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
sizes->surface_depth);
size = mode_cmd.pitches[0] * mode_cmd.height;
DRM_LOCK(drm_dev);
rv = tegra_bo_create(drm_dev, size, &bo);
DRM_UNLOCK(drm_dev);
if (rv != 0)
return (rv);
info = framebuffer_alloc();
if (info == NULL) {
device_printf(drm_dev->dev,
"Cannot allocate DRM framebuffer info.\n");
rv = -ENOMEM;
goto err_object;
}
rv = fb_alloc(drm_dev, &mode_cmd, &bo, 1, &fb);
if (rv != 0) {
device_printf(drm_dev->dev,
"Cannot allocate DRM framebuffer.\n");
goto err_fb;
}
helper->fb = &fb->drm_fb;
helper->fbdev = info;
/* Fill FB info */
info->fb_vbase = bo->vbase;
info->fb_pbase = bo->pbase;
info->fb_size = size;
info->fb_bpp = sizes->surface_bpp;
drm_fb_helper_fill_fix(info, fb->drm_fb.pitches[0], fb->drm_fb.depth);
drm_fb_helper_fill_var(info, helper, fb->drm_fb.width,
fb->drm_fb.height);
DRM_DEBUG_KMS("allocated %dx%d (s %dbits) fb size: %d, bo %p\n",
fb->drm_fb.width, fb->drm_fb.height, fb->drm_fb.depth,
size, bo);
return (1);
err_fb:
drm_gem_object_unreference_unlocked(&bo->gem_obj);
framebuffer_release(info);
err_object:
drm_gem_object_release(&bo->gem_obj);
return (rv);
}
static struct drm_fb_helper_funcs fb_helper_funcs = {
.fb_probe = tegra_fb_probe,
};
/*
* Exported functions
*/
struct fb_info *
tegra_drm_fb_getinfo(struct drm_device *drm_dev)
{
struct tegra_fb *fb;
struct tegra_drm *drm;
drm = container_of(drm_dev, struct tegra_drm, drm_dev);
fb = drm->fb;
if (fb == NULL)
return (NULL);
return (fb->fb_helper.fbdev);
}
struct tegra_bo *
tegra_fb_get_plane(struct tegra_fb *fb, int idx)
{
if (idx >= drm_format_num_planes(fb->drm_fb.pixel_format))
return (NULL);
if (idx >= fb->nplanes)
return (NULL);
return (fb->planes[idx]);
}
int
tegra_drm_fb_init(struct drm_device *drm_dev)
{
struct tegra_fb *fb;
struct tegra_drm *drm;
int rv;
drm = drm_dev->dev_private;
drm = container_of(drm_dev, struct tegra_drm, drm_dev);
fb = malloc(sizeof(*fb), DRM_MEM_DRIVER, M_WAITOK | M_ZERO);
drm->fb = fb;
fb->fb_helper.funcs = &fb_helper_funcs;
rv = drm_fb_helper_init(drm_dev, &fb->fb_helper,
drm_dev->mode_config.num_crtc, drm_dev->mode_config.num_connector);
if (rv != 0) {
device_printf(drm_dev->dev,
"Cannot initialize frame buffer %d\n", rv);
return (rv);
}
rv = drm_fb_helper_single_add_all_connectors(&fb->fb_helper);
if (rv != 0) {
device_printf(drm_dev->dev, "Cannot add all connectors: %d\n",
rv);
goto err_fini;
}
rv = drm_fb_helper_initial_config(&fb->fb_helper, 32);
if (rv != 0) {
device_printf(drm_dev->dev,
"Cannot set initial config: %d\n", rv);
goto err_fini;
}
/* XXXX Setup initial mode for FB */
/* drm_fb_helper_set_par(fb->fb_helper.fbdev); */
return 0;
err_fini:
drm_fb_helper_fini(&fb->fb_helper);
return (rv);
}
int
tegra_drm_fb_create(struct drm_device *drm, struct drm_file *file,
struct drm_mode_fb_cmd2 *cmd, struct drm_framebuffer **fb_res)
{
int hsub, vsub, i;
int width, height, size, bpp;
struct tegra_bo *planes[4];
struct drm_gem_object *gem_obj;
struct tegra_fb *fb;
int rv, nplanes;
hsub = drm_format_horz_chroma_subsampling(cmd->pixel_format);
vsub = drm_format_vert_chroma_subsampling(cmd->pixel_format);
nplanes = drm_format_num_planes(cmd->pixel_format);
for (i = 0; i < nplanes; i++) {
width = cmd->width;
height = cmd->height;
if (i != 0) {
width /= hsub;
height /= vsub;
}
gem_obj = drm_gem_object_lookup(drm, file, cmd->handles[i]);
if (gem_obj == NULL) {
rv = -ENXIO;
goto fail;
}
bpp = drm_format_plane_cpp(cmd->pixel_format, i);
size = (height - 1) * cmd->pitches[i] +
width * bpp + cmd->offsets[i];
if (gem_obj->size < size) {
rv = -EINVAL;
goto fail;
}
planes[i] = container_of(gem_obj, struct tegra_bo, gem_obj);
}
rv = fb_alloc(drm, cmd, planes, nplanes, &fb);
if (rv != 0)
goto fail;
*fb_res = &fb->drm_fb;
return (0);
fail:
while (i--)
drm_gem_object_unreference_unlocked(&planes[i]->gem_obj);
return (rv);
}
void
tegra_drm_fb_destroy(struct drm_device *drm_dev)
{
struct fb_info *info;
struct tegra_fb *fb;
struct tegra_drm *drm;
drm = container_of(drm_dev, struct tegra_drm, drm_dev);
fb = drm->fb;
if (fb == NULL)
return;
info = fb->fb_helper.fbdev;
drm_framebuffer_remove(&fb->drm_fb);
framebuffer_release(info);
drm_fb_helper_fini(&fb->fb_helper);
drm_framebuffer_cleanup(&fb->drm_fb);
free(fb, DRM_MEM_DRIVER);
drm->fb = NULL;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,285 @@
/*-
* Copyright 1992-2016 Michal Meloun
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef _TEGRA_HDMI_REG_H_
#define _TEGRA_HDMI_REG_H_
/*
* !!! WARNING !!!
* Tegra manual uses registers index (and not register addreses).
* We follow the TRM notation and index is converted to offset in
* WR4 / RD4 macros
*/
#define HDMI_NV_PDISP_SOR_STATE0 0x001
#define SOR_STATE0_UPDATE (1 << 0)
#define HDMI_NV_PDISP_SOR_STATE1 0x002
#define SOR_STATE1_ATTACHED (1 << 3)
#define SOR_STATE1_ASY_ORMODE_NORMAL (1 << 2)
#define SOR_STATE1_ASY_HEAD_OPMODE(x) (((x) & 0x3) << 0)
#define ASY_HEAD_OPMODE_SLEEP 0
#define ASY_HEAD_OPMODE_SNOOZE 1
#define ASY_HEAD_OPMODE_AWAKE 2
#define HDMI_NV_PDISP_SOR_STATE2 0x003
#define SOR_STATE2_ASY_DEPOL_NEG (1 << 14)
#define SOR_STATE2_ASY_VSYNCPOL_NEG (1 << 13)
#define SOR_STATE2_ASY_HSYNCPOL_NEG (1 << 12)
#define SOR_STATE2_ASY_PROTOCOL(x) (((x) & 0xf) << 8)
#define ASY_PROTOCOL_SINGLE_TMDS_A 1
#define ASY_PROTOCOL_CUSTOM 15
#define SOR_STATE2_ASY_CRCMODE(x) (((x) & 0x3) << 6)
#define ASY_CRCMODE_ACTIVE 0
#define ASY_CRCMODE_COMPLETE 1
#define ASY_CRCMODE_NON_ACTIVE 2
#define SOR_STATE2_ASY_SUBOWNER(x) (((x) & 0x3) << 4)
#define ASY_SUBOWNER_NONE 0
#define ASY_SUBOWNER_SUBHEAD0 1
#define ASY_SUBOWNER_SUBHEAD1 2
#define SUBOWNER_BOTH 3
#define SOR_STATE2_ASY_OWNER(x) (((x) & 0x3) << 0)
#define ASY_OWNER_NONE 0
#define ASY_OWNER_HEAD0 1
#define HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_CTRL 0x01e
#define AUDIO_INFOFRAME_CTRL_ENABLE (1 << 0)
#define HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_STATUS 0x01f
#define HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_HEADER 0x020
#define HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_SUBPACK0_LOW 0x021
#define HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_SUBPACK0_HIGH 0x022
#define INFOFRAME_HEADER_LEN(x) (((x) & 0x0f) << 16)
#define INFOFRAME_HEADER_VERSION(x) (((x) & 0xff) << 8)
#define INFOFRAME_HEADER_TYPE(x) (((x) & 0xff) << 0)
#define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_CTRL 0x023
#define AVI_INFOFRAME_CTRL_ENABLE (1 << 0)
#define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_STATUS 0x024
#define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_HEADER 0x025
#define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK0_LOW 0x026
#define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK0_HIGH 0x027
#define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK1_LOW 0x028
#define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK1_HIGH 0x029
#define HDMI_NV_PDISP_HDMI_GENERIC_CTRL 0x02a
#define GENERIC_CTRL_AUDIO (1 << 16)
#define GENERIC_CTRL_HBLANK (1 << 12)
#define GENERIC_CTRL_SINGLE (1 << 8)
#define GENERIC_CTRL_OTHER (1 << 4)
#define GENERIC_CTRL_ENABLE (1 << 0)
#define HDMI_NV_PDISP_HDMI_GENERIC_STATUS 0x02b
#define HDMI_NV_PDISP_HDMI_GENERIC_HEADER 0x02c
#define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK0_LOW 0x02d
#define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK0_HIGH 0x02e
#define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK1_LOW 0x02f
#define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK1_HIGH 0x030
#define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK2_LOW 0x031
#define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK2_HIGH 0x032
#define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK3_LOW 0x033
#define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK3_HIGH 0x034
#define HDMI_NV_PDISP_HDMI_ACR_CTRL 0x035
#define HDMI_NV_PDISP_HDMI_ACR_0320_SUBPACK_LOW 0x036
#define HDMI_NV_PDISP_HDMI_ACR_0320_SUBPACK_HIGH 0x037
#define HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_LOW 0x038
#define HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_HIGH 0x039
#define HDMI_NV_PDISP_HDMI_ACR_0882_SUBPACK_LOW 0x03a
#define HDMI_NV_PDISP_HDMI_ACR_0882_SUBPACK_HIGH 0x03b
#define HDMI_NV_PDISP_HDMI_ACR_1764_SUBPACK_LOW 0x03c
#define HDMI_NV_PDISP_HDMI_ACR_1764_SUBPACK_HIGH 0x03d
#define HDMI_NV_PDISP_HDMI_ACR_0480_SUBPACK_LOW 0x03e
#define HDMI_NV_PDISP_HDMI_ACR_0480_SUBPACK_HIGH 0x03f
#define HDMI_NV_PDISP_HDMI_ACR_0960_SUBPACK_LOW 0x040
#define HDMI_NV_PDISP_HDMI_ACR_0960_SUBPACK_HIGH 0x041
#define HDMI_NV_PDISP_HDMI_ACR_1920_SUBPACK_LOW 0x042
#define HDMI_NV_PDISP_HDMI_ACR_1920_SUBPACK_HIGH 0x043
#define ACR_ENABLE (1U << 31)
#define ACR_SUBPACK_CTS(x) (((x) & 0xffffff) << 8)
#define ACR_SUBPACK_N(x) (((x) & 0xffffff) << 0)
#define HDMI_NV_PDISP_HDMI_CTRL 0x044
#define HDMI_CTRL_ENABLE (1 << 30)
#define HDMI_CTRL_CA_SELECT (1 << 28)
#define HDMI_CTRL_SS_SELECT (1 << 27)
#define HDMI_CTRL_SF_SELECT (1 << 26)
#define HDMI_CTRL_CC_SELECT (1 << 25)
#define HDMI_CTRL_CT_SELECT (1 << 24)
#define HDMI_CTRL_MAX_AC_PACKET(x) (((x) & 0x1f) << 16)
#define HDMI_CTRL_SAMPLE_FLAT (1 << 12)
#define HDMI_CTRL_AUDIO_LAYOUT_SELECT (1 << 10)
#define HDMI_CTRL_AUDIO_LAYOUT (1 << 8)
#define HDMI_CTRL_REKEY(x) (((x) & 0x7f) << 0)
#define HDMI_NV_PDISP_HDMI_VSYNC_WINDOW 0x046
#define VSYNC_WINDOW_ENABLE (1U << 31)
#define VSYNC_WINDOW_START(x) (((x) & 0x3ff) << 16)
#define VSYNC_WINDOW_END(x) (((x) & 0x3ff) << 0)
#define HDMI_NV_PDISP_HDMI_SPARE 0x04f
#define SPARE_ACR_PRIORITY (1U << 31)
#define SPARE_CTS_RESET_VAL(x) (((x) & 0x7) << 16)
#define SPARE_SUPRESS_SP_B (1 << 2)
#define SPARE_FORCE_SW_CTS (1 << 1)
#define SPARE_HW_CTS (1 << 0)
#define HDMI_NV_PDISP_SOR_PWR 0x055
#define SOR_PWR_SETTING_NEW (1U << 31)
#define SOR_PWR_SAFE_STATE_PU (1 << 16)
#define SOR_PWR_NORMAL_START_ALT (1 << 1)
#define SOR_PWR_NORMAL_STATE_PU (1 << 0)
#define HDMI_NV_PDISP_SOR_PLL0 0x057
#define SOR_PLL0_TX_REG_LOAD(x) (((x) & 0xf) << 28)
#define SOR_PLL0_ICHPMP(x) (((x) & 0xf) << 24)
#define SOR_PLL0_FILTER(x) (((x) & 0xf) << 16)
#define SOR_PLL0_BG_V17_S(x) (((x) & 0xf) << 12)
#define SOR_PLL0_VCOCAP(x) (((x) & 0xf) << 8)
#define SOR_PLL0_PULLDOWN (1 << 5)
#define SOR_PLL0_RESISTORSEL (1 << 4)
#define SOR_PLL0_PDPORT (1 << 3)
#define SOR_PLL0_VCOPD (1 << 2)
#define SOR_PLL0_PDBG (1 << 1)
#define SOR_PLL0_PWR (1 << 0)
#define HDMI_NV_PDISP_SOR_PLL1 0x058
#define SOR_PLL1_S_D_PIN_PE (1 << 30)
#define SOR_PLL1_HALF_FULL_PE (1 << 29)
#define SOR_PLL1_PE_EN (1 << 28)
#define SOR_PLL1_LOADADJ(x) (((x) & 0xf) << 20)
#define SOR_PLL1_TMDS_TERMADJ(x) (((x) & 0xf) << 9)
#define SOR_PLL1_TMDS_TERM (1 << 8)
#define HDMI_NV_PDISP_SOR_CSTM 0x05a
#define SOR_CSTM_ROTAT(x) (((x) & 0xf) << 28)
#define SOR_CSTM_ROTCLK(x) (((x) & 0xf) << 24)
#define SOR_CSTM_PLLDIV (1 << 21)
#define SOR_CSTM_BALANCED (1 << 19)
#define SOR_CSTM_NEW_MODE (1 << 18)
#define SOR_CSTM_DUP_SYNC (1 << 17)
#define SOR_CSTM_LVDS_ENABLE (1 << 16)
#define SOR_CSTM_LINKACTB (1 << 15)
#define SOR_CSTM_LINKACTA (1 << 14)
#define SOR_CSTM_MODE(x) (((x) & 0x3) << 12)
#define CSTM_MODE_LVDS 0
#define CSTM_MODE_TMDS 1
#define HDMI_NV_PDISP_SOR_SEQ_CTL 0x05f
#define SOR_SEQ_SWITCH (1 << 30)
#define SOR_SEQ_STATUS (1 << 28)
#define SOR_SEQ_PC(x) (((x) & 0xf) << 16)
#define SOR_SEQ_PD_PC_ALT(x) (((x) & 0xf) << 12)
#define SOR_SEQ_PD_PC(x) (((x) & 0xf) << 8)
#define SOR_SEQ_PU_PC_ALT(x) (((x) & 0xf) << 4)
#define SOR_SEQ_PU_PC(x) (((x) & 0xf) << 0)
#define HDMI_NV_PDISP_SOR_SEQ_INST(x) (0x060 + (x))
#define SOR_SEQ_INST_PLL_PULLDOWN (1U << 31)
#define SOR_SEQ_INST_POWERDOWN_MACRO (1 << 30)
#define SOR_SEQ_INST_ASSERT_PLL_RESETV (1 << 29)
#define SOR_SEQ_INST_BLANK_V (1 << 28)
#define SOR_SEQ_INST_BLANK_H (1 << 27)
#define SOR_SEQ_INST_BLANK_DE (1 << 26)
#define SOR_SEQ_INST_BLACK_DATA (1 << 25)
#define SOR_SEQ_INST_TRISTATE_IOS (1 << 24)
#define SOR_SEQ_INST_DRIVE_PWM_OUT_LO (1 << 23)
#define SOR_SEQ_INST_PIN_B_HIGH (1 << 22)
#define SOR_SEQ_INST_PIN_A_HIGH (1 << 21)
#define SOR_SEQ_INST_HALT (1 << 15)
#define SOR_SEQ_INST_WAIT_UNITS(x) (((x) & 0x3) << 12)
#define WAIT_UNITS_US 0
#define WAIT_UNITS_MS 1
#define WAIT_UNITS_VSYNC 2
#define SOR_SEQ_INST_WAIT_TIME(x) (((x) & 0x3ff) << 0)
#define HDMI_NV_PDISP_SOR_LANE_DRIVE_CURRENT 0x07e
#define HDMI_NV_PDISP_AUDIO_N 0x08c
#define AUDIO_N_LOOKUP (1 << 28)
#define AUDIO_N_GENERATE_ALTERNATE (1 << 24)
#define AUDIO_N_RESETF (1 << 20)
#define AUDIO_N_VALUE(x) (((x) & 0xfffff) << 0)
#define HDMI_NV_PDISP_SOR_REFCLK 0x095
#define SOR_REFCLK_DIV_INT(x) (((x) & 0xff) << 8)
#define SOR_REFCLK_DIV_FRAC(x) (((x) & 0x03) << 6)
#define HDMI_NV_PDISP_INPUT_CONTROL 0x097
#define ARM_VIDEO_RANGE_LIMITED (1 << 1)
#define HDMI_SRC_DISPLAYB (1 << 0)
#define HDMI_NV_PDISP_PE_CURRENT 0x099
#define HDMI_NV_PDISP_SOR_AUDIO_CNTRL0 0x0ac
#define SOR_AUDIO_CNTRL0_INJECT_NULLSMPL (1 << 29)
#define SOR_AUDIO_CNTRL0_SOURCE_SELECT(x) (((x) & 0x03) << 20)
#define SOURCE_SELECT_AUTO 0
#define SOURCE_SELECT_SPDIF 1
#define SOURCE_SELECT_HDAL 2
#define SOR_AUDIO_CNTRL0_AFIFO_FLUSH (1 << 12)
#define HDMI_NV_PDISP_SOR_AUDIO_SPARE0 0x0ae
#define SOR_AUDIO_SPARE0_HBR_ENABLE (1 << 27)
#define HDMI_NV_PDISP_SOR_AUDIO_NVAL_0320 0x0af
#define HDMI_NV_PDISP_SOR_AUDIO_NVAL_0441 0x0b0
#define HDMI_NV_PDISP_SOR_AUDIO_NVAL_0882 0x0b1
#define HDMI_NV_PDISP_SOR_AUDIO_NVAL_1764 0x0b2
#define HDMI_NV_PDISP_SOR_AUDIO_NVAL_0480 0x0b3
#define HDMI_NV_PDISP_SOR_AUDIO_NVAL_0960 0x0b4
#define HDMI_NV_PDISP_SOR_AUDIO_NVAL_1920 0x0b5
#define HDMI_NV_PDISP_SOR_AUDIO_HDA_SCRATCH0 0x0b6
#define HDMI_NV_PDISP_SOR_AUDIO_HDA_SCRATCH1 0x0b7
#define HDMI_NV_PDISP_SOR_AUDIO_HDA_SCRATCH2 0x0b8
#define HDMI_NV_PDISP_SOR_AUDIO_HDA_SCRATCH3 0x0b9
#define HDMI_NV_PDISP_SOR_AUDIO_HDA_CODEC_SCRATCH0 0x0ba
#define HDMI_NV_PDISP_SOR_AUDIO_HDA_CODEC_SCRATCH1 0x0bb
#define HDMI_NV_PDISP_SOR_AUDIO_HDA_ELD_BUFWR 0x0bc
#define HDMI_NV_PDISP_SOR_AUDIO_HDA_PRESENSE 0x0bd
#define SOR_AUDIO_HDA_PRESENSE_VALID (1 << 1)
#define SOR_AUDIO_HDA_PRESENSE_PRESENT (1 << 0)
#define HDMI_NV_PDISP_SOR_AUDIO_AVAL_0320 0x0bf
#define HDMI_NV_PDISP_SOR_AUDIO_AVAL_0441 0x0c0
#define HDMI_NV_PDISP_SOR_AUDIO_AVAL_0882 0x0c1
#define HDMI_NV_PDISP_SOR_AUDIO_AVAL_1764 0x0c2
#define HDMI_NV_PDISP_SOR_AUDIO_AVAL_0480 0x0c3
#define HDMI_NV_PDISP_SOR_AUDIO_AVAL_0960 0x0c4
#define HDMI_NV_PDISP_SOR_AUDIO_AVAL_1920 0x0c5
#define HDMI_NV_PDISP_SOR_AUDIO_AVAL_DEFAULT 0x0c6
#define HDMI_NV_PDISP_INT_STATUS 0x0cc
#define INT_SCRATCH (1 << 3)
#define INT_CP_REQUEST (1 << 2)
#define INT_CODEC_SCRATCH1 (1 << 1)
#define INT_CODEC_SCRATCH0 (1 << 0)
#define HDMI_NV_PDISP_INT_MASK 0x0cd
#define HDMI_NV_PDISP_INT_ENABLE 0x0ce
#define HDMI_NV_PDISP_SOR_IO_PEAK_CURRENT 0x0d1
#define HDMI_NV_PDISP_SOR_PAD_CTLS0 0x0d2
#endif /* _TEGRA_HDMI_REG_H_ */

View File

@ -0,0 +1,650 @@
/*-
* Copyright (c) 2015 Michal Meloun
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/clock.h>
#include <sys/kernel.h>
#include <sys/limits.h>
#include <sys/lock.h>
#include <sys/module.h>
#include <sys/resource.h>
#include <sys/sx.h>
#include <sys/rman.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <dev/extres/clk/clk.h>
#include <dev/extres/hwreset/hwreset.h>
#include <dev/drm2/drmP.h>
#include <dev/drm2/drm_crtc_helper.h>
#include <dev/drm2/drm_fb_helper.h>
#include <dev/fdt/simplebus.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
#include <arm/nvidia/drm2/tegra_drm.h>
#include "fb_if.h"
#include "tegra_drm_if.h"
#define WR4(_sc, _r, _v) bus_rite_4((_sc)->mem_res, (_r), (_v))
#define RD4(_sc, _r) bus_read_4((_sc)->mem_res, (_r))
#define LOCK(_sc) sx_xlock(&(_sc)->lock)
#define UNLOCK(_sc) sx_xunlock(&(_sc)->lock)
#define SLEEP(_sc, timeout) sx_sleep(sc, &sc->lock, 0, "host1x", timeout);
#define LOCK_INIT(_sc) sx_init(&_sc->lock, "host1x")
#define LOCK_DESTROY(_sc) sx_destroy(&_sc->lock)
#define ASSERT_LOCKED(_sc) sx_assert(&_sc->lock, SA_LOCKED)
#define ASSERT_UNLOCKED(_sc) sx_assert(&_sc->lock, SA_UNLOCKED)
static struct ofw_compat_data compat_data[] = {
{"nvidia,tegra124-host1x", 1},
{NULL, 0}
};
#define DRIVER_NAME "tegra"
#define DRIVER_DESC "NVIDIA Tegra TK1"
#define DRIVER_DATE "20151101"
#define DRIVER_MAJOR 0
#define DRIVER_MINOR 0
#define DRIVER_PATCHLEVEL 0
struct client_info;
TAILQ_HEAD(client_list, client_info);
typedef struct client_list client_list_t;
struct client_info {
TAILQ_ENTRY(client_info) list_e;
device_t client;
int activated;
};
struct host1x_softc {
struct simplebus_softc simplebus_sc; /* must be first */
device_t dev;
struct sx lock;
int attach_done;
struct resource *mem_res;
struct resource *syncpt_irq_res;
void *syncpt_irq_h;
struct resource *gen_irq_res;
void *gen_irq_h;
clk_t clk;
hwreset_t reset;
struct intr_config_hook irq_hook;
int drm_inited;
client_list_t clients;
struct tegra_drm *tegra_drm;
};
static void
host1x_output_poll_changed(struct drm_device *drm_dev)
{
struct tegra_drm *drm;
drm = container_of(drm_dev, struct tegra_drm, drm_dev);
if (drm->fb != NULL)
drm_fb_helper_hotplug_event(&drm->fb->fb_helper);
}
static const struct drm_mode_config_funcs mode_config_funcs = {
.fb_create = tegra_drm_fb_create,
.output_poll_changed = host1x_output_poll_changed,
};
static int
host1x_drm_init(struct host1x_softc *sc)
{
struct client_info *entry;
int rv;
LOCK(sc);
TAILQ_FOREACH(entry, &sc->clients, list_e) {
if (entry->activated)
continue;
rv = TEGRA_DRM_INIT_CLIENT(entry->client, sc->dev,
sc->tegra_drm);
if (rv != 0) {
device_printf(sc->dev,
"Cannot init DRM client %s: %d\n",
device_get_name(entry->client), rv);
return (rv);
}
entry->activated = 1;
}
UNLOCK(sc);
return (0);
}
static int
host1x_drm_exit(struct host1x_softc *sc)
{
struct client_info *entry;
int rv;
#ifdef FREEBSD_NOTYET
struct drm_device *dev, *tmp;
#endif
LOCK(sc);
if (!sc->drm_inited) {
UNLOCK(sc);
return (0);
}
TAILQ_FOREACH_REVERSE(entry, &sc->clients, client_list, list_e) {
if (!entry->activated)
continue;
rv = TEGRA_DRM_EXIT_CLIENT(entry->client, sc->dev,
sc->tegra_drm);
if (rv != 0) {
device_printf(sc->dev,
"Cannot exit DRM client %s: %d\n",
device_get_name(entry->client), rv);
}
entry->activated = 0;
}
#ifdef FREEBSD_NOTYET
list_for_each_entry_safe(dev, tmp, &driver->device_list, driver_item)
drm_put_dev(dev);
#endif
sc->drm_inited = 0;
UNLOCK(sc);
return (0);
}
static int
host1x_drm_load(struct drm_device *drm_dev, unsigned long flags)
{
struct host1x_softc *sc;
int rv;
sc = device_get_softc(drm_dev->dev);
drm_mode_config_init(drm_dev);
drm_dev->mode_config.min_width = 32;
drm_dev->mode_config.min_height = 32;
drm_dev->mode_config.max_width = 4096;
drm_dev->mode_config.max_height = 4096;
drm_dev->mode_config.funcs = &mode_config_funcs;
rv = host1x_drm_init(sc);
if (rv != 0)
goto fail_host1x;
drm_dev->irq_enabled = true;
drm_dev->max_vblank_count = 0xffffffff;
drm_dev->vblank_disable_allowed = true;
rv = drm_vblank_init(drm_dev, drm_dev->mode_config.num_crtc);
if (rv != 0)
goto fail_vblank;
drm_mode_config_reset(drm_dev);
rv = tegra_drm_fb_init(drm_dev);
if (rv != 0)
goto fail_fb;
drm_kms_helper_poll_init(drm_dev);
return (0);
fail_fb:
tegra_drm_fb_destroy(drm_dev);
drm_vblank_cleanup(drm_dev);
fail_vblank:
host1x_drm_exit(sc);
fail_host1x:
drm_mode_config_cleanup(drm_dev);
return (rv);
}
static int
host1x_drm_unload(struct drm_device *drm_dev)
{
struct host1x_softc *sc;
int rv;
sc = device_get_softc(drm_dev->dev);
drm_kms_helper_poll_fini(drm_dev);
tegra_drm_fb_destroy(drm_dev);
drm_mode_config_cleanup(drm_dev);
rv = host1x_drm_exit(sc);
if (rv < 0)
return (rv);
return (0);
}
static int
host1x_drm_open(struct drm_device *drm_dev, struct drm_file *filp)
{
return (0);
}
static void
tegra_drm_preclose(struct drm_device *drm, struct drm_file *file)
{
struct drm_crtc *crtc;
list_for_each_entry(crtc, &drm->mode_config.crtc_list, head)
tegra_dc_cancel_page_flip(crtc, file);
}
static void
host1x_drm_lastclose(struct drm_device *drm_dev)
{
struct tegra_drm *drm;
drm = container_of(drm_dev, struct tegra_drm, drm_dev);
if (drm->fb != NULL)
drm_fb_helper_restore_fbdev_mode(&drm->fb->fb_helper);
}
static int
host1x_drm_enable_vblank(struct drm_device *drm_dev, int pipe)
{
struct drm_crtc *crtc;
list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head) {
if (pipe == tegra_dc_get_pipe(crtc)) {
tegra_dc_enable_vblank(crtc);
return (0);
}
}
return (-ENODEV);
}
static void
host1x_drm_disable_vblank(struct drm_device *drm_dev, int pipe)
{
struct drm_crtc *crtc;
list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head) {
if (pipe == tegra_dc_get_pipe(crtc)) {
tegra_dc_disable_vblank(crtc);
return;
}
}
}
static struct drm_ioctl_desc host1x_drm_ioctls[] = {
};
struct drm_driver tegra_drm_driver = {
.driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME,
.load = host1x_drm_load,
.unload = host1x_drm_unload,
.open = host1x_drm_open,
.preclose = tegra_drm_preclose,
.lastclose = host1x_drm_lastclose,
.get_vblank_counter = drm_vblank_count,
.enable_vblank = host1x_drm_enable_vblank,
.disable_vblank = host1x_drm_disable_vblank,
/* Fields filled by tegra_bo_driver_register()
.gem_free_object
.gem_pager_ops
.dumb_create
.dumb_map_offset
.dumb_destroy
*/
.ioctls = host1x_drm_ioctls,
.num_ioctls = nitems(host1x_drm_ioctls),
.name = DRIVER_NAME,
.desc = DRIVER_DESC,
.date = DRIVER_DATE,
.major = DRIVER_MAJOR,
.minor = DRIVER_MINOR,
.patchlevel = DRIVER_PATCHLEVEL,
};
/*
* ----------------- Device methods -------------------------
*/
static void
host1x_irq_hook(void *arg)
{
struct host1x_softc *sc;
int rv;
sc = arg;
config_intrhook_disestablish(&sc->irq_hook);
tegra_bo_driver_register(&tegra_drm_driver);
rv = drm_get_platform_dev(sc->dev, &sc->tegra_drm->drm_dev,
&tegra_drm_driver);
if (rv != 0) {
device_printf(sc->dev, "drm_get_platform_dev(): %d\n", rv);
return;
}
sc->drm_inited = 1;
}
static struct fb_info *
host1x_fb_helper_getinfo(device_t dev)
{
struct host1x_softc *sc;
sc = device_get_softc(dev);
if (sc->tegra_drm == NULL)
return (NULL);
return (tegra_drm_fb_getinfo(&sc->tegra_drm->drm_dev));
}
static int
host1x_register_client(device_t dev, device_t client)
{
struct host1x_softc *sc;
struct client_info *entry;
sc = device_get_softc(dev);
entry = malloc(sizeof(struct client_info), M_DEVBUF, M_WAITOK | M_ZERO);
entry->client = client;
entry->activated = 0;
LOCK(sc);
TAILQ_INSERT_TAIL(&sc->clients, entry, list_e);
UNLOCK(sc);
return (0);
}
static int
host1x_deregister_client(device_t dev, device_t client)
{
struct host1x_softc *sc;
struct client_info *entry;
sc = device_get_softc(dev);
LOCK(sc);
TAILQ_FOREACH(entry, &sc->clients, list_e) {
if (entry->client == client) {
if (entry->activated)
panic("Tegra DRM: Attempt to deregister "
"activated client");
TAILQ_REMOVE(&sc->clients, entry, list_e);
free(entry, M_DEVBUF);
UNLOCK(sc);
return (0);
}
}
UNLOCK(sc);
return (0);
}
static void
host1x_gen_intr(void *arg)
{
struct host1x_softc *sc;
sc = (struct host1x_softc *)arg;
LOCK(sc);
UNLOCK(sc);
}
static void
host1x_syncpt_intr(void *arg)
{
struct host1x_softc *sc;
sc = (struct host1x_softc *)arg;
LOCK(sc);
UNLOCK(sc);
}
static void
host1x_new_pass(device_t dev)
{
struct host1x_softc *sc;
int rv, rid;
phandle_t node;
/*
* We attach during BUS_PASS_BUS (because we must overcome simplebus),
* but some of our FDT resources are not ready until BUS_PASS_DEFAULT
*/
sc = device_get_softc(dev);
if (sc->attach_done || bus_current_pass < BUS_PASS_DEFAULT) {
bus_generic_new_pass(dev);
return;
}
sc->attach_done = 1;
node = ofw_bus_get_node(dev);
/* Allocate our IRQ resource. */
rid = 0;
sc->syncpt_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
RF_ACTIVE);
if (sc->syncpt_irq_res == NULL) {
device_printf(dev, "Cannot allocate interrupt.\n");
rv = ENXIO;
goto fail;
}
rid = 1;
sc->gen_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
RF_ACTIVE);
if (sc->gen_irq_res == NULL) {
device_printf(dev, "Cannot allocate interrupt.\n");
rv = ENXIO;
goto fail;
}
/* FDT resources */
rv = hwreset_get_by_ofw_name(sc->dev, 0, "host1x", &sc->reset);
if (rv != 0) {
device_printf(dev, "Cannot get fuse reset\n");
goto fail;
}
rv = clk_get_by_ofw_index(sc->dev, 0, 0, &sc->clk);
if (rv != 0) {
device_printf(dev, "Cannot get i2c clock: %d\n", rv);
goto fail;
}
rv = clk_enable(sc->clk);
if (rv != 0) {
device_printf(dev, "Cannot enable clock: %d\n", rv);
goto fail;
}
rv = hwreset_deassert(sc->reset);
if (rv != 0) {
device_printf(sc->dev, "Cannot clear reset\n");
goto fail;
}
/* Setup interrupts */
rv = bus_setup_intr(dev, sc->gen_irq_res,
INTR_TYPE_MISC | INTR_MPSAFE, NULL, host1x_gen_intr,
sc, &sc->gen_irq_h);
if (rv) {
device_printf(dev, "Cannot setup gen interrupt.\n");
goto fail;
}
rv = bus_setup_intr(dev, sc->syncpt_irq_res,
INTR_TYPE_MISC | INTR_MPSAFE, NULL, host1x_syncpt_intr,
sc, &sc->syncpt_irq_h);
if (rv) {
device_printf(dev, "Cannot setup syncpt interrupt.\n");
goto fail;
}
simplebus_init(dev, 0);
for (node = OF_child(node); node > 0; node = OF_peer(node))
simplebus_add_device(dev, node, 0, NULL, -1, NULL);
sc->irq_hook.ich_func = host1x_irq_hook;
sc->irq_hook.ich_arg = sc;
config_intrhook_establish(&sc->irq_hook);
bus_generic_new_pass(dev);
return;
fail:
device_detach(dev);
return;
}
static int
host1x_probe(device_t dev)
{
if (!ofw_bus_status_okay(dev))
return (ENXIO);
if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
return (ENXIO);
return (BUS_PROBE_DEFAULT);
}
static int
host1x_attach(device_t dev)
{
int rv, rid;
struct host1x_softc *sc;
sc = device_get_softc(dev);
sc->tegra_drm = malloc(sizeof(struct tegra_drm), DRM_MEM_DRIVER,
M_WAITOK | M_ZERO);
/* crosslink together all worlds */
sc->dev = dev;
sc->tegra_drm->drm_dev.dev_private = &sc->tegra_drm;
sc->tegra_drm->drm_dev.dev = dev;
TAILQ_INIT(&sc->clients);
LOCK_INIT(sc);
/* Get the memory resource for the register mapping. */
rid = 0;
sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
RF_ACTIVE);
if (sc->mem_res == NULL) {
device_printf(dev, "Cannot map registers.\n");
rv = ENXIO;
goto fail;
}
return (bus_generic_attach(dev));
fail:
if (sc->tegra_drm != NULL)
free(sc->tegra_drm, DRM_MEM_DRIVER);
if (sc->mem_res != NULL)
bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
LOCK_DESTROY(sc);
return (rv);
}
static int
host1x_detach(device_t dev)
{
struct host1x_softc *sc;
sc = device_get_softc(dev);
host1x_drm_exit(sc);
if (sc->gen_irq_h != NULL)
bus_teardown_intr(dev, sc->gen_irq_res, sc->gen_irq_h);
if (sc->tegra_drm != NULL)
free(sc->tegra_drm, DRM_MEM_DRIVER);
if (sc->clk != NULL)
clk_release(sc->clk);
if (sc->reset != NULL)
hwreset_release(sc->reset);
if (sc->syncpt_irq_h != NULL)
bus_teardown_intr(dev, sc->syncpt_irq_res, sc->syncpt_irq_h);
if (sc->gen_irq_res != NULL)
bus_release_resource(dev, SYS_RES_IRQ, 1, sc->gen_irq_res);
if (sc->syncpt_irq_res != NULL)
bus_release_resource(dev, SYS_RES_IRQ, 0, sc->syncpt_irq_res);
if (sc->mem_res != NULL)
bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
LOCK_DESTROY(sc);
return (bus_generic_detach(dev));
}
static device_method_t host1x_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, host1x_probe),
DEVMETHOD(device_attach, host1x_attach),
DEVMETHOD(device_detach, host1x_detach),
/* Bus interface */
DEVMETHOD(bus_new_pass, host1x_new_pass),
/* Framebuffer service methods */
DEVMETHOD(fb_getinfo, host1x_fb_helper_getinfo),
/* tegra drm interface */
DEVMETHOD(tegra_drm_register_client, host1x_register_client),
DEVMETHOD(tegra_drm_deregister_client, host1x_deregister_client),
DEVMETHOD_END
};
static devclass_t host1x_devclass;
DEFINE_CLASS_1(host1x, host1x_driver, host1x_methods,
sizeof(struct host1x_softc), simplebus_driver);
EARLY_DRIVER_MODULE(host1x, simplebus, host1x_driver,
host1x_devclass, 0, 0, BUS_PASS_BUS);
/* Bindings for fbd device. */
extern devclass_t fbd_devclass;
extern driver_t fbd_driver;
DRIVER_MODULE(fbd, host1x, fbd_driver, fbd_devclass, 0, 0);

View File

@ -36,15 +36,15 @@ arm/nvidia/tegra_soctherm.c standard
arm/nvidia/tegra_lic.c standard
arm/nvidia/tegra_mc.c standard
#arm/nvidia/tegra_hda.c optional snd_hda
#arm/nvidia/drm2/hdmi.c optional drm2
#arm/nvidia/drm2/tegra_drm_if.m optional drm2
#arm/nvidia/drm2/tegra_drm_subr.c optional drm2
#arm/nvidia/drm2/tegra_host1x.c optional drm2
#arm/nvidia/drm2/tegra_hdmi.c optional drm2
#arm/nvidia/drm2/tegra_dc_if.m optional drm2
#arm/nvidia/drm2/tegra_dc.c optional drm2
#arm/nvidia/drm2/tegra_fb.c optional drm2
#arm/nvidia/drm2/tegra_bo.c optional drm2
arm/nvidia/drm2/hdmi.c optional drm2
arm/nvidia/drm2/tegra_drm_if.m optional drm2
arm/nvidia/drm2/tegra_drm_subr.c optional drm2
arm/nvidia/drm2/tegra_host1x.c optional drm2
arm/nvidia/drm2/tegra_hdmi.c optional drm2
arm/nvidia/drm2/tegra_dc_if.m optional drm2
arm/nvidia/drm2/tegra_dc.c optional drm2
arm/nvidia/drm2/tegra_fb.c optional drm2
arm/nvidia/drm2/tegra_bo.c optional drm2
#
# Firmware
#