Commit 71e8831f authored by Andy Gross's avatar Andy Gross Committed by Greg Kroah-Hartman

drm/omap: DMM/TILER support for OMAP4+ platform

Dynamic Memory Manager (DMM) is a hardware block in the OMAP4+
processor that contains at least one TILER instance.  TILER, or
Tiling and Isometric Lightweight Engine for Rotation, provides
IOMMU capabilities through the use of a physical address translation
table.  The TILER also provides zero cost rotation and mirroring.

The TILER provides both 1D and 2D access by providing different views
or address ranges that can be used to access the physical memory that
has been mapped in through the PAT.  Access to the 1D view results in
linear access to the underlying memory.  Access to the 2D views result
in tiled access to the underlying memory resulted in increased
efficiency.

The TILER address space is managed by a tiler container manager (TCM)
and allocates the address space through the use of the Simple Tiler
Allocation algorithm (SiTA).  The purpose of the algorithm is to keep
fragmentation of the address space as low as possible.
Signed-off-by: default avatarAndy Gross <andy.gross@ti.com>
Signed-off-by: default avatarRob Clark <rob@ti.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent e0134715
......@@ -4,7 +4,15 @@
#
ccflags-y := -Iinclude/drm -Werror
omapdrm-y := omap_drv.o omap_crtc.o omap_encoder.o omap_connector.o omap_fb.o omap_fbdev.o omap_gem.o
omapdrm-y := omap_drv.o \
omap_crtc.o \
omap_encoder.o \
omap_connector.o \
omap_fb.o \
omap_fbdev.o \
omap_gem.o \
omap_dmm_tiler.o \
tcm-sita.o
# temporary:
omapdrm-y += omap_gem_helpers.o
......
......@@ -22,6 +22,7 @@ TODO
. Review DSS vs KMS mismatches. The omap_dss_device is sort of part encoder,
part connector. Which results in a bit of duct tape to fwd calls from
encoder to connector. Possibly this could be done a bit better.
. Add debugfs information for DMM/TILER
Userspace:
. git://github.com/robclark/xf86-video-omap.git
......
/*
*
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
* Author: Rob Clark <rob@ti.com>
* Andy Gross <andy.gross@ti.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef OMAP_DMM_PRIV_H
#define OMAP_DMM_PRIV_H
#define DMM_REVISION 0x000
#define DMM_HWINFO 0x004
#define DMM_LISA_HWINFO 0x008
#define DMM_DMM_SYSCONFIG 0x010
#define DMM_LISA_LOCK 0x01C
#define DMM_LISA_MAP__0 0x040
#define DMM_LISA_MAP__1 0x044
#define DMM_TILER_HWINFO 0x208
#define DMM_TILER_OR__0 0x220
#define DMM_TILER_OR__1 0x224
#define DMM_PAT_HWINFO 0x408
#define DMM_PAT_GEOMETRY 0x40C
#define DMM_PAT_CONFIG 0x410
#define DMM_PAT_VIEW__0 0x420
#define DMM_PAT_VIEW__1 0x424
#define DMM_PAT_VIEW_MAP__0 0x440
#define DMM_PAT_VIEW_MAP_BASE 0x460
#define DMM_PAT_IRQ_EOI 0x478
#define DMM_PAT_IRQSTATUS_RAW 0x480
#define DMM_PAT_IRQSTATUS 0x490
#define DMM_PAT_IRQENABLE_SET 0x4A0
#define DMM_PAT_IRQENABLE_CLR 0x4B0
#define DMM_PAT_STATUS__0 0x4C0
#define DMM_PAT_STATUS__1 0x4C4
#define DMM_PAT_STATUS__2 0x4C8
#define DMM_PAT_STATUS__3 0x4CC
#define DMM_PAT_DESCR__0 0x500
#define DMM_PAT_DESCR__1 0x510
#define DMM_PAT_DESCR__2 0x520
#define DMM_PAT_DESCR__3 0x530
#define DMM_PEG_HWINFO 0x608
#define DMM_PEG_PRIO 0x620
#define DMM_PEG_PRIO_PAT 0x640
#define DMM_IRQSTAT_DST (1<<0)
#define DMM_IRQSTAT_LST (1<<1)
#define DMM_IRQSTAT_ERR_INV_DSC (1<<2)
#define DMM_IRQSTAT_ERR_INV_DATA (1<<3)
#define DMM_IRQSTAT_ERR_UPD_AREA (1<<4)
#define DMM_IRQSTAT_ERR_UPD_CTRL (1<<5)
#define DMM_IRQSTAT_ERR_UPD_DATA (1<<6)
#define DMM_IRQSTAT_ERR_LUT_MISS (1<<7)
#define DMM_IRQSTAT_ERR_MASK (DMM_IRQ_STAT_ERR_INV_DSC | \
DMM_IRQ_STAT_ERR_INV_DATA | \
DMM_IRQ_STAT_ERR_UPD_AREA | \
DMM_IRQ_STAT_ERR_UPD_CTRL | \
DMM_IRQ_STAT_ERR_UPD_DATA | \
DMM_IRQ_STAT_ERR_LUT_MISS)
#define DMM_PATSTATUS_READY (1<<0)
#define DMM_PATSTATUS_VALID (1<<1)
#define DMM_PATSTATUS_RUN (1<<2)
#define DMM_PATSTATUS_DONE (1<<3)
#define DMM_PATSTATUS_LINKED (1<<4)
#define DMM_PATSTATUS_BYPASSED (1<<7)
#define DMM_PATSTATUS_ERR_INV_DESCR (1<<10)
#define DMM_PATSTATUS_ERR_INV_DATA (1<<11)
#define DMM_PATSTATUS_ERR_UPD_AREA (1<<12)
#define DMM_PATSTATUS_ERR_UPD_CTRL (1<<13)
#define DMM_PATSTATUS_ERR_UPD_DATA (1<<14)
#define DMM_PATSTATUS_ERR_ACCESS (1<<15)
#define DMM_PATSTATUS_ERR (DMM_PATSTATUS_ERR_INV_DESCR | \
DMM_PATSTATUS_ERR_INV_DATA | \
DMM_PATSTATUS_ERR_UPD_AREA | \
DMM_PATSTATUS_ERR_UPD_CTRL | \
DMM_PATSTATUS_ERR_UPD_DATA | \
DMM_PATSTATUS_ERR_ACCESS)
enum {
PAT_STATUS,
PAT_DESCR
};
struct pat_ctrl {
u32 start:4;
u32 dir:4;
u32 lut_id:8;
u32 sync:12;
u32 ini:4;
};
struct pat {
uint32_t next_pa;
struct pat_area area;
struct pat_ctrl ctrl;
uint32_t data_pa;
};
#define DMM_FIXED_RETRY_COUNT 1000
/* create refill buffer big enough to refill all slots, plus 3 descriptors..
* 3 descriptors is probably the worst-case for # of 2d-slices in a 1d area,
* but I guess you don't hit that worst case at the same time as full area
* refill
*/
#define DESCR_SIZE 128
#define REFILL_BUFFER_SIZE ((4 * 128 * 256) + (3 * DESCR_SIZE))
struct dmm;
struct dmm_txn {
void *engine_handle;
struct tcm *tcm;
uint8_t *current_va;
dma_addr_t current_pa;
struct pat *last_pat;
};
struct refill_engine {
int id;
struct dmm *dmm;
struct tcm *tcm;
uint8_t *refill_va;
dma_addr_t refill_pa;
/* only one trans per engine for now */
struct dmm_txn txn;
/* offset to lut associated with container */
u32 *lut_offset;
wait_queue_head_t wait_for_refill;
struct list_head idle_node;
};
struct dmm {
struct device *dev;
void __iomem *base;
int irq;
struct page *dummy_page;
dma_addr_t dummy_pa;
void *refill_va;
dma_addr_t refill_pa;
/* refill engines */
struct semaphore engine_sem;
struct list_head idle_head;
struct refill_engine *engines;
int num_engines;
/* container information */
int container_width;
int container_height;
int lut_width;
int lut_height;
int num_lut;
/* array of LUT - TCM containers */
struct tcm **tcm;
/* LUT table storage */
u32 *lut;
/* allocation list and lock */
struct list_head alloc_head;
spinlock_t list_lock;
};
#endif
This diff is collapsed.
/*
*
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
* Author: Rob Clark <rob@ti.com>
* Andy Gross <andy.gross@ti.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef OMAP_DMM_TILER_H
#define OMAP_DMM_TILER_H
#include "omap_drv.h"
#include "tcm.h"
enum tiler_fmt {
TILFMT_8BIT = 0,
TILFMT_16BIT,
TILFMT_32BIT,
TILFMT_PAGE,
TILFMT_NFORMATS
};
struct pat_area {
u32 x0:8;
u32 y0:8;
u32 x1:8;
u32 y1:8;
};
struct tiler_block {
struct list_head alloc_node; /* node for global block list */
struct tcm_area area; /* area */
enum tiler_fmt fmt; /* format */
};
/* bits representing the same slot in DMM-TILER hw-block */
#define SLOT_WIDTH_BITS 6
#define SLOT_HEIGHT_BITS 6
/* bits reserved to describe coordinates in DMM-TILER hw-block */
#define CONT_WIDTH_BITS 14
#define CONT_HEIGHT_BITS 13
/* calculated constants */
#define TILER_PAGE (1 << (SLOT_WIDTH_BITS + SLOT_HEIGHT_BITS))
#define TILER_WIDTH (1 << (CONT_WIDTH_BITS - SLOT_WIDTH_BITS))
#define TILER_HEIGHT (1 << (CONT_HEIGHT_BITS - SLOT_HEIGHT_BITS))
/* tiler space addressing bitfields */
#define MASK_XY_FLIP (1 << 31)
#define MASK_Y_INVERT (1 << 30)
#define MASK_X_INVERT (1 << 29)
#define SHIFT_ACC_MODE 27
#define MASK_ACC_MODE 3
#define MASK(bits) ((1 << (bits)) - 1)
#define TILVIEW_8BIT 0x60000000u
#define TILVIEW_16BIT (TILVIEW_8BIT + VIEW_SIZE)
#define TILVIEW_32BIT (TILVIEW_16BIT + VIEW_SIZE)
#define TILVIEW_PAGE (TILVIEW_32BIT + VIEW_SIZE)
#define TILVIEW_END (TILVIEW_PAGE + VIEW_SIZE)
/* create tsptr by adding view orientation and access mode */
#define TIL_ADDR(x, orient, a)\
((u32) (x) | (orient) | ((a) << SHIFT_ACC_MODE))
/* externally accessible functions */
int omap_dmm_init(struct drm_device *dev);
int omap_dmm_remove(void);
/* pin/unpin */
int tiler_pin(struct tiler_block *block, struct page **pages, bool wait);
int tiler_unpin(struct tiler_block *block);
/* reserve/release */
struct tiler_block *tiler_reserve_2d(enum tiler_fmt fmt, uint16_t w, uint16_t h,
uint16_t align);
struct tiler_block *tiler_reserve_1d(size_t size);
int tiler_release(struct tiler_block *block);
/* utilities */
dma_addr_t tiler_ssptr(struct tiler_block *block);
uint32_t tiler_stride(enum tiler_fmt fmt);
size_t tiler_size(enum tiler_fmt fmt, uint16_t w, uint16_t h);
size_t tiler_vsize(enum tiler_fmt fmt, uint16_t w, uint16_t h);
void tiler_align(enum tiler_fmt fmt, uint16_t *w, uint16_t *h);
/* GEM bo flags -> tiler fmt */
static inline enum tiler_fmt gem2fmt(uint32_t flags)
{
switch (flags & OMAP_BO_TILED) {
case OMAP_BO_TILED_8:
return TILFMT_8BIT;
case OMAP_BO_TILED_16:
return TILFMT_16BIT;
case OMAP_BO_TILED_32:
return TILFMT_32BIT;
default:
return TILFMT_PAGE;
}
}
static inline bool validfmt(enum tiler_fmt fmt)
{
switch (fmt) {
case TILFMT_8BIT:
case TILFMT_16BIT:
case TILFMT_32BIT:
case TILFMT_PAGE:
return true;
default:
return false;
}
}
struct omap_dmm_platform_data {
void __iomem *base;
int irq;
};
#endif
......@@ -20,7 +20,7 @@
#ifndef __OMAP_DRM_H__
#define __OMAP_DRM_H__
#include "drm.h"
#include <drm/drm.h>
/* Please note that modifications to all structs defined here are
* subject to backwards-compatibility constraints.
......
......@@ -290,6 +290,7 @@ static unsigned int detect_connectors(struct drm_device *dev)
static int omap_modeset_init(struct drm_device *dev)
{
const struct omap_drm_platform_data *pdata = dev->dev->platform_data;
struct omap_kms_platform_data *kms_pdata = NULL;
struct omap_drm_private *priv = dev->dev_private;
struct omap_dss_device *dssdev = NULL;
int i, j;
......@@ -297,23 +298,27 @@ static int omap_modeset_init(struct drm_device *dev)
drm_mode_config_init(dev);
if (pdata) {
if (pdata && pdata->kms_pdata) {
kms_pdata = pdata->kms_pdata;
/* if platform data is provided by the board file, use it to
* control which overlays, managers, and devices we own.
*/
for (i = 0; i < pdata->mgr_cnt; i++) {
for (i = 0; i < kms_pdata->mgr_cnt; i++) {
struct omap_overlay_manager *mgr =
omap_dss_get_overlay_manager(pdata->mgr_ids[i]);
omap_dss_get_overlay_manager(
kms_pdata->mgr_ids[i]);
create_encoder(dev, mgr);
}
for (i = 0; i < pdata->dev_cnt; i++) {
for (i = 0; i < kms_pdata->dev_cnt; i++) {
struct omap_dss_device *dssdev =
omap_dss_find_device(
(void *)pdata->dev_names[i], match_dev_name);
(void *)kms_pdata->dev_names[i],
match_dev_name);
if (!dssdev) {
dev_warn(dev->dev, "no such dssdev: %s\n",
pdata->dev_names[i]);
kms_pdata->dev_names[i]);
continue;
}
create_connector(dev, dssdev);
......@@ -322,9 +327,9 @@ static int omap_modeset_init(struct drm_device *dev)
connected_connectors = detect_connectors(dev);
j = 0;
for (i = 0; i < pdata->ovl_cnt; i++) {
for (i = 0; i < kms_pdata->ovl_cnt; i++) {
struct omap_overlay *ovl =
omap_dss_get_overlay(pdata->ovl_ids[i]);
omap_dss_get_overlay(kms_pdata->ovl_ids[i]);
create_crtc(dev, ovl, &j, connected_connectors);
}
} else {
......
......@@ -30,7 +30,7 @@
* detected devices. This should be a good default behavior for most cases,
* but yet there still might be times when you wish to do something different.
*/
struct omap_drm_platform_data {
struct omap_kms_platform_data {
int ovl_cnt;
const int *ovl_ids;
int mgr_cnt;
......@@ -39,4 +39,9 @@ struct omap_drm_platform_data {
const char **dev_names;
};
struct omap_drm_platform_data {
struct omap_kms_platform_data *kms_pdata;
struct omap_dmm_platform_data *dmm_pdata;
};
#endif /* __OMAP_DRM_H__ */
This diff is collapsed.
/*
* tcm_sita.h
*
* SImple Tiler Allocator (SiTA) private structures.
*
* Author: Ravi Ramachandra <r.ramachandra@ti.com>
*
* Copyright (C) 2009-2011 Texas Instruments, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * 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.
*
* * Neither the name of Texas Instruments Incorporated nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
*/
#ifndef _TCM_SITA_H
#define _TCM_SITA_H
#include "tcm.h"
/* length between two coordinates */
#define LEN(a, b) ((a) > (b) ? (a) - (b) + 1 : (b) - (a) + 1)
enum criteria {
CR_MAX_NEIGHS = 0x01,
CR_FIRST_FOUND = 0x10,
CR_BIAS_HORIZONTAL = 0x20,
CR_BIAS_VERTICAL = 0x40,
CR_DIAGONAL_BALANCE = 0x80
};
/* nearness to the beginning of the search field from 0 to 1000 */
struct nearness_factor {
s32 x;
s32 y;
};
/*
* Statistics on immediately neighboring slots. Edge is the number of
* border segments that are also border segments of the scan field. Busy
* refers to the number of neighbors that are occupied.
*/
struct neighbor_stats {
u16 edge;
u16 busy;
};
/* structure to keep the score of a potential allocation */
struct score {
struct nearness_factor f;
struct neighbor_stats n;
struct tcm_area a;
u16 neighs; /* number of busy neighbors */
};
struct sita_pvt {
spinlock_t lock; /* spinlock to protect access */
struct tcm_pt div_pt; /* divider point splitting container */
struct tcm_area ***map; /* pointers to the parent area for each slot */
};
/* assign coordinates to area */
static inline
void assign(struct tcm_area *a, u16 x0, u16 y0, u16 x1, u16 y1)
{
a->p0.x = x0;
a->p0.y = y0;
a->p1.x = x1;
a->p1.y = y1;
}
#endif
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment