731 lines
18 KiB
C
Executable File
731 lines
18 KiB
C
Executable File
/*
|
|
* Copyright (c) 2016 Samsung Electronics Co., Ltd.
|
|
* http://www.samsung.com
|
|
*
|
|
* Helper file for Samsung EXYNOS DPU driver
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*/
|
|
|
|
#include <linux/clk.h>
|
|
#include <linux/err.h>
|
|
#include <linux/pm_runtime.h>
|
|
#include <asm/cacheflush.h>
|
|
#include <asm/page.h>
|
|
#if defined(CONFIG_EXYNOS_CONTENT_PATH_PROTECTION)
|
|
#include <linux/smc.h>
|
|
#endif
|
|
#if defined(CONFIG_SUPPORT_LEGACY_ION)
|
|
#include <linux/exynos_iovmm.h>
|
|
#endif
|
|
|
|
#include "decon.h"
|
|
#include "dsim.h"
|
|
#include "dpp.h"
|
|
#if defined(CONFIG_EXYNOS_DISPLAYPORT)
|
|
#include "displayport.h"
|
|
#endif
|
|
#include "./panels/lcd_ctrl.h"
|
|
#include <video/mipi_display.h>
|
|
|
|
static int __dpu_match_dev(struct device *dev, void *data)
|
|
{
|
|
struct dpp_device *dpp;
|
|
struct dsim_device *dsim;
|
|
#if defined(CONFIG_EXYNOS_DISPLAYPORT)
|
|
struct displayport_device *displayport;
|
|
#endif
|
|
struct decon_device *decon = (struct decon_device *)data;
|
|
|
|
decon_dbg("%s: drvname(%s)\n", __func__, dev->driver->name);
|
|
|
|
if (!strcmp(DPP_MODULE_NAME, dev->driver->name)) {
|
|
dpp = (struct dpp_device *)dev_get_drvdata(dev);
|
|
decon->dpp_sd[dpp->id] = &dpp->sd;
|
|
decon_dbg("dpp%d sd name(%s) attr(0x%lx)\n", dpp->id,
|
|
decon->dpp_sd[dpp->id]->name, dpp->attr);
|
|
} else if (!strcmp(DSIM_MODULE_NAME, dev->driver->name)) {
|
|
dsim = (struct dsim_device *)dev_get_drvdata(dev);
|
|
decon->dsim_sd[dsim->id] = &dsim->sd;
|
|
decon_dbg("dsim sd name(%s)\n", dsim->sd.name);
|
|
#if defined(CONFIG_EXYNOS_DISPLAYPORT)
|
|
} else if (!strcmp(DISPLAYPORT_MODULE_NAME, dev->driver->name)) {
|
|
displayport = (struct displayport_device *)dev_get_drvdata(dev);
|
|
decon->displayport_sd = &displayport->sd;
|
|
decon_dbg("displayport sd name(%s)\n", displayport->sd.name);
|
|
#endif
|
|
} else {
|
|
decon_err("failed to get driver name\n");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int dpu_get_sd_by_drvname(struct decon_device *decon, char *drvname)
|
|
{
|
|
struct device_driver *drv;
|
|
struct device *dev;
|
|
|
|
drv = driver_find(drvname, &platform_bus_type);
|
|
if (IS_ERR_OR_NULL(drv)) {
|
|
decon_err("failed to find driver\n");
|
|
return -ENODEV;
|
|
}
|
|
|
|
dev = driver_find_device(drv, NULL, decon, __dpu_match_dev);
|
|
|
|
return 0;
|
|
}
|
|
|
|
u32 dpu_translate_fmt_to_dpp(u32 format)
|
|
{
|
|
switch (format) {
|
|
/* YUV420 */
|
|
case DECON_PIXEL_FORMAT_NV12:
|
|
return DECON_PIXEL_FORMAT_NV21;
|
|
case DECON_PIXEL_FORMAT_NV21:
|
|
return DECON_PIXEL_FORMAT_NV12;
|
|
case DECON_PIXEL_FORMAT_NV12N_10B:
|
|
return DECON_PIXEL_FORMAT_NV12N_10B;
|
|
case DECON_PIXEL_FORMAT_NV12M:
|
|
return DECON_PIXEL_FORMAT_NV21M;
|
|
case DECON_PIXEL_FORMAT_NV21M:
|
|
return DECON_PIXEL_FORMAT_NV12M;
|
|
case DECON_PIXEL_FORMAT_NV12N:
|
|
return DECON_PIXEL_FORMAT_NV12N;
|
|
case DECON_PIXEL_FORMAT_YUV420:
|
|
return DECON_PIXEL_FORMAT_YVU420;
|
|
case DECON_PIXEL_FORMAT_YVU420:
|
|
return DECON_PIXEL_FORMAT_YUV420;
|
|
case DECON_PIXEL_FORMAT_YUV420M:
|
|
return DECON_PIXEL_FORMAT_YVU420M;
|
|
case DECON_PIXEL_FORMAT_YVU420M:
|
|
return DECON_PIXEL_FORMAT_YUV420M;
|
|
/* YUV422 */
|
|
case DECON_PIXEL_FORMAT_NV16:
|
|
return DECON_PIXEL_FORMAT_NV61;
|
|
case DECON_PIXEL_FORMAT_NV61:
|
|
return DECON_PIXEL_FORMAT_NV16;
|
|
/* RGB32 */
|
|
case DECON_PIXEL_FORMAT_ARGB_8888:
|
|
return DECON_PIXEL_FORMAT_BGRA_8888;
|
|
case DECON_PIXEL_FORMAT_ABGR_8888:
|
|
return DECON_PIXEL_FORMAT_RGBA_8888;
|
|
case DECON_PIXEL_FORMAT_RGBA_8888:
|
|
return DECON_PIXEL_FORMAT_ABGR_8888;
|
|
case DECON_PIXEL_FORMAT_BGRA_8888:
|
|
return DECON_PIXEL_FORMAT_ARGB_8888;
|
|
case DECON_PIXEL_FORMAT_XRGB_8888:
|
|
return DECON_PIXEL_FORMAT_BGRX_8888;
|
|
case DECON_PIXEL_FORMAT_XBGR_8888:
|
|
return DECON_PIXEL_FORMAT_RGBX_8888;
|
|
case DECON_PIXEL_FORMAT_RGBX_8888:
|
|
return DECON_PIXEL_FORMAT_XBGR_8888;
|
|
case DECON_PIXEL_FORMAT_BGRX_8888:
|
|
return DECON_PIXEL_FORMAT_XRGB_8888;
|
|
default:
|
|
return format;
|
|
}
|
|
}
|
|
|
|
u32 dpu_get_bpp(enum decon_pixel_format fmt)
|
|
{
|
|
switch (fmt) {
|
|
case DECON_PIXEL_FORMAT_ARGB_8888:
|
|
case DECON_PIXEL_FORMAT_ABGR_8888:
|
|
case DECON_PIXEL_FORMAT_RGBA_8888:
|
|
case DECON_PIXEL_FORMAT_BGRA_8888:
|
|
case DECON_PIXEL_FORMAT_XRGB_8888:
|
|
case DECON_PIXEL_FORMAT_XBGR_8888:
|
|
case DECON_PIXEL_FORMAT_RGBX_8888:
|
|
case DECON_PIXEL_FORMAT_BGRX_8888:
|
|
case DECON_PIXEL_FORMAT_ARGB_2101010:
|
|
case DECON_PIXEL_FORMAT_ABGR_2101010:
|
|
case DECON_PIXEL_FORMAT_RGBA_1010102:
|
|
case DECON_PIXEL_FORMAT_BGRA_1010102:
|
|
return 32;
|
|
|
|
case DECON_PIXEL_FORMAT_RGBA_5551:
|
|
case DECON_PIXEL_FORMAT_RGB_565:
|
|
case DECON_PIXEL_FORMAT_BGR_565:
|
|
return 16;
|
|
|
|
case DECON_PIXEL_FORMAT_NV12N_10B:
|
|
case DECON_PIXEL_FORMAT_NV12M_S10B:
|
|
case DECON_PIXEL_FORMAT_NV21M_S10B:
|
|
case DECON_PIXEL_FORMAT_NV12M_P010:
|
|
case DECON_PIXEL_FORMAT_NV21M_P010:
|
|
/* YUV422 */
|
|
case DECON_PIXEL_FORMAT_NV16M_P210:
|
|
case DECON_PIXEL_FORMAT_NV61M_P210:
|
|
case DECON_PIXEL_FORMAT_NV16M_S10B:
|
|
case DECON_PIXEL_FORMAT_NV61M_S10B:
|
|
return 15;
|
|
|
|
case DECON_PIXEL_FORMAT_NV12:
|
|
case DECON_PIXEL_FORMAT_NV21:
|
|
case DECON_PIXEL_FORMAT_NV12M:
|
|
case DECON_PIXEL_FORMAT_NV21M:
|
|
case DECON_PIXEL_FORMAT_YUV420:
|
|
case DECON_PIXEL_FORMAT_YVU420:
|
|
case DECON_PIXEL_FORMAT_YUV420M:
|
|
case DECON_PIXEL_FORMAT_YVU420M:
|
|
case DECON_PIXEL_FORMAT_NV12N:
|
|
/* YUV422 */
|
|
case DECON_PIXEL_FORMAT_NV16:
|
|
case DECON_PIXEL_FORMAT_NV61:
|
|
case DECON_PIXEL_FORMAT_YVU422_3P:
|
|
return 12;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int dpu_get_meta_plane_cnt(enum decon_pixel_format format)
|
|
{
|
|
switch (format) {
|
|
case DECON_PIXEL_FORMAT_ARGB_8888:
|
|
case DECON_PIXEL_FORMAT_ABGR_8888:
|
|
case DECON_PIXEL_FORMAT_RGBA_8888:
|
|
case DECON_PIXEL_FORMAT_BGRA_8888:
|
|
case DECON_PIXEL_FORMAT_XRGB_8888:
|
|
case DECON_PIXEL_FORMAT_XBGR_8888:
|
|
case DECON_PIXEL_FORMAT_RGBX_8888:
|
|
case DECON_PIXEL_FORMAT_BGRX_8888:
|
|
case DECON_PIXEL_FORMAT_RGBA_5551:
|
|
case DECON_PIXEL_FORMAT_RGB_565:
|
|
case DECON_PIXEL_FORMAT_BGR_565:
|
|
case DECON_PIXEL_FORMAT_NV12N:
|
|
case DECON_PIXEL_FORMAT_NV16:
|
|
case DECON_PIXEL_FORMAT_NV61:
|
|
case DECON_PIXEL_FORMAT_NV12:
|
|
case DECON_PIXEL_FORMAT_NV21:
|
|
case DECON_PIXEL_FORMAT_NV12M:
|
|
case DECON_PIXEL_FORMAT_NV21M:
|
|
case DECON_PIXEL_FORMAT_YVU422_3P:
|
|
case DECON_PIXEL_FORMAT_YUV420:
|
|
case DECON_PIXEL_FORMAT_YVU420:
|
|
case DECON_PIXEL_FORMAT_YUV420M:
|
|
case DECON_PIXEL_FORMAT_YVU420M:
|
|
return -1;
|
|
|
|
case DECON_PIXEL_FORMAT_NV12N_10B:
|
|
case DECON_PIXEL_FORMAT_ARGB_2101010:
|
|
case DECON_PIXEL_FORMAT_ABGR_2101010:
|
|
case DECON_PIXEL_FORMAT_RGBA_1010102:
|
|
case DECON_PIXEL_FORMAT_BGRA_1010102:
|
|
return 1;
|
|
|
|
case DECON_PIXEL_FORMAT_NV12M_P010:
|
|
case DECON_PIXEL_FORMAT_NV21M_P010:
|
|
case DECON_PIXEL_FORMAT_NV12M_S10B:
|
|
case DECON_PIXEL_FORMAT_NV21M_S10B:
|
|
|
|
case DECON_PIXEL_FORMAT_NV16M_P210:
|
|
case DECON_PIXEL_FORMAT_NV61M_P210:
|
|
case DECON_PIXEL_FORMAT_NV16M_S10B:
|
|
case DECON_PIXEL_FORMAT_NV61M_S10B:
|
|
return 2;
|
|
|
|
default:
|
|
decon_err("%s: invalid format(%d)\n", __func__, format);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
int dpu_get_plane_cnt(enum decon_pixel_format format, bool is_hdr)
|
|
{
|
|
switch (format) {
|
|
case DECON_PIXEL_FORMAT_ARGB_8888:
|
|
case DECON_PIXEL_FORMAT_ABGR_8888:
|
|
case DECON_PIXEL_FORMAT_RGBA_8888:
|
|
case DECON_PIXEL_FORMAT_BGRA_8888:
|
|
case DECON_PIXEL_FORMAT_XRGB_8888:
|
|
case DECON_PIXEL_FORMAT_XBGR_8888:
|
|
case DECON_PIXEL_FORMAT_RGBX_8888:
|
|
case DECON_PIXEL_FORMAT_BGRX_8888:
|
|
case DECON_PIXEL_FORMAT_RGBA_5551:
|
|
case DECON_PIXEL_FORMAT_RGB_565:
|
|
case DECON_PIXEL_FORMAT_BGR_565:
|
|
case DECON_PIXEL_FORMAT_NV12N:
|
|
return 1;
|
|
|
|
case DECON_PIXEL_FORMAT_NV12N_10B:
|
|
case DECON_PIXEL_FORMAT_ARGB_2101010:
|
|
case DECON_PIXEL_FORMAT_ABGR_2101010:
|
|
case DECON_PIXEL_FORMAT_RGBA_1010102:
|
|
case DECON_PIXEL_FORMAT_BGRA_1010102:
|
|
if (is_hdr)
|
|
return 2;
|
|
else
|
|
return 1;
|
|
|
|
case DECON_PIXEL_FORMAT_NV16:
|
|
case DECON_PIXEL_FORMAT_NV61:
|
|
case DECON_PIXEL_FORMAT_NV12:
|
|
case DECON_PIXEL_FORMAT_NV21:
|
|
case DECON_PIXEL_FORMAT_NV12M:
|
|
case DECON_PIXEL_FORMAT_NV21M:
|
|
return 2;
|
|
|
|
case DECON_PIXEL_FORMAT_NV12M_P010:
|
|
case DECON_PIXEL_FORMAT_NV21M_P010:
|
|
case DECON_PIXEL_FORMAT_NV12M_S10B:
|
|
case DECON_PIXEL_FORMAT_NV21M_S10B:
|
|
|
|
case DECON_PIXEL_FORMAT_NV16M_P210:
|
|
case DECON_PIXEL_FORMAT_NV61M_P210:
|
|
case DECON_PIXEL_FORMAT_NV16M_S10B:
|
|
case DECON_PIXEL_FORMAT_NV61M_S10B:
|
|
if (is_hdr)
|
|
return 3;
|
|
else
|
|
return 2;
|
|
|
|
case DECON_PIXEL_FORMAT_YVU422_3P:
|
|
case DECON_PIXEL_FORMAT_YUV420:
|
|
case DECON_PIXEL_FORMAT_YVU420:
|
|
case DECON_PIXEL_FORMAT_YUV420M:
|
|
case DECON_PIXEL_FORMAT_YVU420M:
|
|
return 3;
|
|
|
|
default:
|
|
decon_err("%s: invalid format(%d)\n", __func__, format);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
u32 dpu_get_alpha_len(int format)
|
|
{
|
|
switch (format) {
|
|
case DECON_PIXEL_FORMAT_ARGB_8888:
|
|
case DECON_PIXEL_FORMAT_ABGR_8888:
|
|
case DECON_PIXEL_FORMAT_RGBA_8888:
|
|
case DECON_PIXEL_FORMAT_BGRA_8888:
|
|
return 8;
|
|
|
|
case DECON_PIXEL_FORMAT_ABGR_4444:
|
|
case DECON_PIXEL_FORMAT_RGBA_4444:
|
|
case DECON_PIXEL_FORMAT_BGRA_4444:
|
|
return 4;
|
|
|
|
case DECON_PIXEL_FORMAT_ARGB_2101010:
|
|
case DECON_PIXEL_FORMAT_ABGR_2101010:
|
|
case DECON_PIXEL_FORMAT_RGBA_1010102:
|
|
case DECON_PIXEL_FORMAT_BGRA_1010102:
|
|
return 2;
|
|
|
|
case DECON_PIXEL_FORMAT_RGBA_5551:
|
|
case DECON_PIXEL_FORMAT_BGRA_5551:
|
|
return 1;
|
|
|
|
case DECON_PIXEL_FORMAT_XRGB_8888:
|
|
case DECON_PIXEL_FORMAT_XBGR_8888:
|
|
case DECON_PIXEL_FORMAT_RGBX_8888:
|
|
case DECON_PIXEL_FORMAT_BGRX_8888:
|
|
case DECON_PIXEL_FORMAT_RGB_565:
|
|
case DECON_PIXEL_FORMAT_BGR_565:
|
|
return 0;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
bool decon_intersect(struct decon_rect *r1, struct decon_rect *r2)
|
|
{
|
|
return !(r1->left >= r2->right || r1->right <= r2->left ||
|
|
r1->top >= r2->bottom || r1->bottom <= r2->top);
|
|
}
|
|
|
|
int decon_intersection(struct decon_rect *r1,
|
|
struct decon_rect *r2, struct decon_rect *r3)
|
|
{
|
|
r3->top = max(r1->top, r2->top);
|
|
r3->bottom = min(r1->bottom, r2->bottom);
|
|
r3->left = max(r1->left, r2->left);
|
|
r3->right = min(r1->right, r2->right);
|
|
return 0;
|
|
}
|
|
|
|
bool is_decon_rect_differ(struct decon_rect *r1, struct decon_rect *r2)
|
|
{
|
|
return ((r1->left != r2->left) || (r1->top != r2->top) ||
|
|
(r1->right != r2->right) || (r1->bottom != r2->bottom));
|
|
}
|
|
|
|
bool is_scaling(struct decon_win_config *config)
|
|
{
|
|
return (config->dst.w != config->src.w) || (config->dst.h != config->src.h);
|
|
}
|
|
|
|
bool is_full(struct decon_rect *r, struct decon_lcd *lcd)
|
|
{
|
|
return (r->left == 0) && (r->top == 0) &&
|
|
(r->right == lcd->xres - 1) && (r->bottom == lcd->yres - 1);
|
|
}
|
|
|
|
bool is_rgb32(int format)
|
|
{
|
|
switch (format) {
|
|
case DECON_PIXEL_FORMAT_ARGB_8888:
|
|
case DECON_PIXEL_FORMAT_ABGR_8888:
|
|
case DECON_PIXEL_FORMAT_RGBA_8888:
|
|
case DECON_PIXEL_FORMAT_BGRA_8888:
|
|
case DECON_PIXEL_FORMAT_XRGB_8888:
|
|
case DECON_PIXEL_FORMAT_XBGR_8888:
|
|
case DECON_PIXEL_FORMAT_RGBX_8888:
|
|
case DECON_PIXEL_FORMAT_BGRX_8888:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool is_decon_opaque_format(int format)
|
|
{
|
|
switch (format) {
|
|
case DECON_PIXEL_FORMAT_RGBA_8888:
|
|
case DECON_PIXEL_FORMAT_BGRA_8888:
|
|
case DECON_PIXEL_FORMAT_RGBA_5551:
|
|
case DECON_PIXEL_FORMAT_ARGB_8888:
|
|
case DECON_PIXEL_FORMAT_ABGR_8888:
|
|
case DECON_PIXEL_FORMAT_ARGB_2101010:
|
|
case DECON_PIXEL_FORMAT_ABGR_2101010:
|
|
case DECON_PIXEL_FORMAT_RGBA_1010102:
|
|
case DECON_PIXEL_FORMAT_BGRA_1010102:
|
|
return false;
|
|
|
|
default:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
void dpu_unify_rect(struct decon_rect *r1, struct decon_rect *r2,
|
|
struct decon_rect *dst)
|
|
{
|
|
dst->top = min(r1->top, r2->top);
|
|
dst->bottom = max(r1->bottom, r2->bottom);
|
|
dst->left = min(r1->right, r2->right);
|
|
dst->right = max(r1->right, r2->right);
|
|
}
|
|
|
|
void decon_to_psr_info(struct decon_device *decon, struct decon_mode_info *psr)
|
|
{
|
|
psr->psr_mode = decon->dt.psr_mode;
|
|
psr->trig_mode = decon->dt.trig_mode;
|
|
psr->dsi_mode = decon->dt.dsi_mode;
|
|
psr->out_type = decon->dt.out_type;
|
|
}
|
|
|
|
void decon_to_init_param(struct decon_device *decon, struct decon_param *p)
|
|
{
|
|
struct decon_lcd *lcd_info = decon->lcd_info;
|
|
struct v4l2_mbus_framefmt mbus_fmt;
|
|
|
|
mbus_fmt.width = 0;
|
|
mbus_fmt.height = 0;
|
|
mbus_fmt.code = 0;
|
|
mbus_fmt.field = 0;
|
|
mbus_fmt.colorspace = 0;
|
|
|
|
p->lcd_info = lcd_info;
|
|
p->psr.psr_mode = decon->dt.psr_mode;
|
|
p->psr.trig_mode = decon->dt.trig_mode;
|
|
p->psr.dsi_mode = decon->dt.dsi_mode;
|
|
p->psr.out_type = decon->dt.out_type;
|
|
p->nr_windows = decon->dt.max_win;
|
|
p->disp_ss_regs = decon->res.ss_regs;
|
|
decon_dbg("%s: psr(%d) trig(%d) dsi(%d) out(%d) wins(%d) LCD[%d %d]\n",
|
|
__func__, p->psr.psr_mode, p->psr.trig_mode,
|
|
p->psr.dsi_mode, p->psr.out_type, p->nr_windows,
|
|
decon->lcd_info->xres, decon->lcd_info->yres);
|
|
}
|
|
|
|
void dpu_debug_printk(const char *function_name, const char *format, ...)
|
|
{
|
|
struct va_format vaf;
|
|
va_list args;
|
|
|
|
va_start(args, format);
|
|
vaf.fmt = format;
|
|
vaf.va = &args;
|
|
|
|
printk(KERN_INFO "[%s] %pV", function_name, &vaf);
|
|
|
|
va_end(args);
|
|
}
|
|
|
|
void __iomem *dpu_get_sysreg_addr(void)
|
|
{
|
|
void __iomem *regs;
|
|
|
|
if (of_have_populated_dt()) {
|
|
struct device_node *nd;
|
|
nd = of_find_compatible_node(NULL, NULL,
|
|
"samsung,exynos9-disp_ss");
|
|
if (!nd) {
|
|
decon_err("failed find compatible node(sysreg-disp)");
|
|
return NULL;
|
|
}
|
|
|
|
regs = of_iomap(nd, 0);
|
|
if (!regs) {
|
|
decon_err("Failed to get sysreg-disp address.");
|
|
return NULL;
|
|
}
|
|
} else {
|
|
decon_err("failed have populated device tree");
|
|
return NULL;
|
|
}
|
|
|
|
return regs;
|
|
}
|
|
|
|
#if defined(CONFIG_EXYNOS_CONTENT_PATH_PROTECTION)
|
|
static int decon_get_protect_id(int dma_id)
|
|
{
|
|
int prot_id = 0;
|
|
|
|
switch (dma_id) {
|
|
case IDMA_G0:
|
|
prot_id = PROT_G0;
|
|
break;
|
|
case IDMA_G1:
|
|
prot_id = PROT_G1;
|
|
break;
|
|
case IDMA_GF:
|
|
prot_id = PROT_GF;
|
|
break;
|
|
case IDMA_VG0:
|
|
prot_id = PROT_VG0;
|
|
break;
|
|
default:
|
|
decon_err("Unknown DMA_ID (%d)\n", dma_id);
|
|
break;
|
|
}
|
|
|
|
return prot_id;
|
|
}
|
|
|
|
static int decon_control_protection(int dma_id, bool en)
|
|
{
|
|
int ret = SUCCESS_EXYNOS_SMC;
|
|
int prot_id;
|
|
|
|
prot_id = decon_get_protect_id(dma_id);
|
|
ret = exynos_smc(SMC_PROTECTION_SET, 0, prot_id,
|
|
(en ? SMC_PROTECTION_ENABLE : SMC_PROTECTION_DISABLE));
|
|
|
|
if (ret)
|
|
decon_err("DMA%d (en=%d): exynos_smc call fail (err=%d)\n",
|
|
dma_id, en, ret);
|
|
else
|
|
decon_dbg("DMA%d protection %s\n",
|
|
dma_id, en ? "enabled" : "disabled");
|
|
|
|
return ret;
|
|
}
|
|
|
|
void decon_set_protected_content(struct decon_device *decon,
|
|
struct decon_reg_data *regs)
|
|
{
|
|
bool en;
|
|
int dma_id, i, ret = 0;
|
|
u32 change = 0;
|
|
u32 cur_protect_bits = 0;
|
|
|
|
/* IDMA protection configs (G0,G1,VG0,VG1,VGF0,VGF1) */
|
|
for (i = 0; i < decon->dt.max_win; i++) {
|
|
if (!regs)
|
|
break;
|
|
|
|
cur_protect_bits |=
|
|
(regs->protection[i] << regs->dpp_config[i].idma_type);
|
|
}
|
|
|
|
/* ODMA protection config (WB: writeback) */
|
|
if (decon->dt.out_type == DECON_OUT_WB)
|
|
if (regs)
|
|
cur_protect_bits |= (regs->protection[decon->dt.max_win] << ODMA_WB);
|
|
|
|
if (decon->prev_protection_bitmask != cur_protect_bits) {
|
|
|
|
/* apply protection configs for each DMA */
|
|
for (dma_id = 0; dma_id < decon->dt.max_win; dma_id++) {
|
|
/*
|
|
* This loop should use max_win instead of dpp_cnt,
|
|
* because dpp_cnt includes writeback case
|
|
*/
|
|
en = cur_protect_bits & (1 << dma_id);
|
|
|
|
change = (cur_protect_bits & (1 << dma_id)) ^
|
|
(decon->prev_protection_bitmask & (1 << dma_id));
|
|
|
|
if (change)
|
|
ret = decon_control_protection(dma_id, en);
|
|
}
|
|
}
|
|
|
|
/* save current portection configs */
|
|
decon->prev_protection_bitmask = cur_protect_bits;
|
|
}
|
|
#endif
|
|
|
|
#if defined(DPU_DUMP_BUFFER_IRQ)
|
|
/* id : VGF0=0, VGF1=1 */
|
|
static void dpu_dump_data_to_console(void *v_addr, int buf_size, int id)
|
|
{
|
|
dpp_info("=== (CH#%d) Frame Buffer Data(128 Bytes) ===\n", id);
|
|
|
|
print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 32, 4,
|
|
v_addr, buf_size, false);
|
|
}
|
|
|
|
void dpu_dump_afbc_info(void)
|
|
{
|
|
int i, j;
|
|
struct decon_device *decon;
|
|
struct dpu_afbc_info *afbc_info;
|
|
void *v_addr[MAX_DECON_WIN];
|
|
int size[MAX_DECON_WIN];
|
|
int decon_cnt;
|
|
|
|
decon_cnt = get_decon_drvdata(0)->dt.decon_cnt;
|
|
|
|
for (i = 0; i < decon_cnt; i++) {
|
|
decon = get_decon_drvdata(i);
|
|
if (decon == NULL)
|
|
continue;
|
|
|
|
afbc_info = &decon->d.prev_afbc_info;
|
|
decon_info("%s: previous AFBC channel information\n", __func__);
|
|
for (j = 0; j < decon->dt.max_win; ++j) { /* all the dpp that has afbc */
|
|
if (!afbc_info->is_afbc[j])
|
|
continue;
|
|
|
|
v_addr[j] = dma_buf_vmap(afbc_info->dma_buf[j]);
|
|
size[j] = afbc_info->dma_buf[j]->size;
|
|
decon_info("\t[DMA%d] Base(0x%p), KV(0x%p), size(%d)\n",
|
|
j, (void *)afbc_info->dma_addr[j],
|
|
v_addr[j], size[j]);
|
|
dma_buf_vunmap(afbc_info->dma_buf[j], v_addr[j]);
|
|
}
|
|
|
|
afbc_info = &decon->d.cur_afbc_info;
|
|
decon_info("%s: current AFBC channel information\n", __func__);
|
|
for (j = 0; j < decon->dt.max_win; ++j) { /* all the dpp that has afbc */
|
|
if (!afbc_info->is_afbc[j])
|
|
continue;
|
|
|
|
v_addr[j] = dma_buf_vmap(afbc_info->dma_buf[j]);
|
|
size[j] = afbc_info->dma_buf[j]->size;
|
|
decon_info("\t[DMA%d] Base(0x%p), KV(0x%p), size(%d)\n",
|
|
j, (void *)afbc_info->dma_addr[j],
|
|
v_addr[j], size[j]);
|
|
dma_buf_vunmap(afbc_info->dma_buf[j], v_addr[j]);
|
|
}
|
|
}
|
|
}
|
|
|
|
static int dpu_dump_buffer_data(struct dpp_device *dpp)
|
|
{
|
|
int i;
|
|
int id_idx = 0;
|
|
int dump_size = 128;
|
|
int decon_cnt;
|
|
struct decon_device *decon;
|
|
struct dpu_afbc_info *afbc_info;
|
|
|
|
decon_cnt = get_decon_drvdata(0)->dt.decon_cnt;
|
|
|
|
if (dpp->state == DPP_STATE_ON) {
|
|
|
|
for (i = 0; i < decon_cnt; i++) {
|
|
decon = get_decon_drvdata(i);
|
|
if (decon == NULL)
|
|
continue;
|
|
|
|
id_idx = dpp->id;
|
|
|
|
afbc_info = &decon->d.cur_afbc_info;
|
|
if (!afbc_info->is_afbc[id_idx])
|
|
continue;
|
|
|
|
if (afbc_info->dma_buf[id_idx]->size > 2048)
|
|
dump_size = 128;
|
|
else
|
|
dump_size = afbc_info->dma_buf[id_idx]->size / 16;
|
|
|
|
decon_info("Base(0x%p), KV(0x%p), size(%d)\n",
|
|
(void *)afbc_info->dma_addr[id_idx],
|
|
afbc_info->dma_v_addr[id_idx], dump_size);
|
|
|
|
dpu_dump_data_to_console(afbc_info->dma_v_addr[id_idx],
|
|
dump_size, dpp->id);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
int dpu_sysmmu_fault_handler(struct iommu_domain *domain,
|
|
struct device *dev, unsigned long iova, int flags, void *token)
|
|
{
|
|
struct decon_device *decon = NULL;
|
|
|
|
if (!strcmp(DSIM_MODULE_NAME, dev->driver->name)) {
|
|
decon = get_decon_drvdata(0);
|
|
#if defined(CONFIG_EXYNOS_DISPLAYPORT)
|
|
} else if (!strcmp(DISPLAYPORT_MODULE_NAME, dev->driver->name)) {
|
|
decon = get_decon_drvdata(2);
|
|
#endif
|
|
} else {
|
|
decon_err("unknown driver for dpu sysmmu falut handler(%s)\n",
|
|
dev->driver->name);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (decon)
|
|
decon_dump(decon);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if defined(CONFIG_EXYNOS_PD)
|
|
int dpu_pm_domain_check_status(struct exynos_pm_domain *pm_domain)
|
|
{
|
|
if (!pm_domain || !pm_domain->check_status)
|
|
return 0;
|
|
|
|
if (pm_domain->check_status(pm_domain))
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
void dsim_to_regs_param(struct dsim_device *dsim, struct dsim_regs *regs)
|
|
{
|
|
if (dsim->res.regs)
|
|
regs->regs = dsim->res.regs;
|
|
else
|
|
regs->regs = NULL;
|
|
|
|
if (dsim->res.phy_regs)
|
|
regs->phy_regs = dsim->res.phy_regs;
|
|
else
|
|
regs->phy_regs = NULL;
|
|
|
|
if (dsim->res.phy_regs_ex)
|
|
regs->phy_regs_ex = dsim->res.phy_regs_ex;
|
|
else
|
|
regs->phy_regs_ex = NULL;
|
|
}
|