Files
android_kernel_samsung_sm86…/rotator/sde_rotator_r1_ctl.c
Narendra Muppalla 3709853456 Display drivers kernel project initial snapshot
This change brings msm display driver including sde,
dp, dsi, rotator, dsi pll and dp pll from base 4.19 kernel
project. It is first source code snapshot from base kernel project.

Change-Id: Iec864c064ce5ea04e170f24414c728684002f284
Signed-off-by: Narendra Muppalla <NarendraM@codeaurora.org>
2019-04-14 22:20:59 -07:00

260 righe
5.6 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
*/
#define pr_fmt(fmt) "%s: " fmt, __func__
#include <linux/errno.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
#include <linux/sort.h>
#include <linux/clk.h>
#include <linux/bitmap.h>
#include "sde_rotator_r1_hwio.h"
#include "sde_rotator_util.h"
#include "sde_rotator_r1_internal.h"
#include "sde_rotator_core.h"
struct sde_mdp_ctl *sde_mdp_ctl_alloc(struct sde_rot_data_type *mdata,
u32 off)
{
struct sde_mdp_ctl *ctl = NULL;
static struct sde_mdp_ctl sde_ctl[5];
static const u32 offset[] = {0x00002000, 0x00002200, 0x00002400,
0x00002600, 0x00002800};
if (off >= ARRAY_SIZE(offset)) {
SDEROT_ERR("invalid parameters\n");
return ERR_PTR(-EINVAL);
}
ctl = &sde_ctl[off];
ctl->mdata = mdata;
ctl->num = off;
ctl->offset = offset[ctl->num];
ctl->base = mdata->sde_io.base + ctl->offset;
return ctl;
}
int sde_mdp_ctl_free(struct sde_mdp_ctl *ctl)
{
if (!ctl)
return -ENODEV;
if (ctl->wb)
sde_mdp_wb_free(ctl->wb);
ctl->is_secure = false;
ctl->mixer_left = NULL;
ctl->mixer_right = NULL;
ctl->wb = NULL;
memset(&ctl->ops, 0, sizeof(ctl->ops));
return 0;
}
struct sde_mdp_mixer *sde_mdp_mixer_assign(u32 id, bool wb)
{
struct sde_mdp_mixer *mixer = NULL;
struct sde_rot_data_type *mdata = sde_rot_get_mdata();
static struct sde_mdp_mixer sde_mixer[16];
static const u32 offset[] = {0x00048000, 0x00049000};
if (id >= ARRAY_SIZE(offset)) {
SDEROT_ERR("invalid parameters\n");
return ERR_PTR(-EINVAL);
}
mixer = &sde_mixer[id];
mixer->num = id;
mixer->offset = offset[mixer->num];
mixer->base = mdata->sde_io.base + mixer->offset;
return mixer;
}
static void sde_mdp_mixer_setup(struct sde_mdp_ctl *master_ctl,
int mixer_mux)
{
int i;
struct sde_mdp_ctl *ctl = NULL;
struct sde_mdp_mixer *mixer = sde_mdp_mixer_get(master_ctl,
mixer_mux);
if (!mixer)
return;
ctl = mixer->ctl;
if (!ctl)
return;
/* check if mixer setup for rotator is needed */
if (mixer->rotator_mode) {
int nmixers = 5;
for (i = 0; i < nmixers; i++)
sde_mdp_ctl_write(ctl, SDE_MDP_REG_CTL_LAYER(i), 0);
return;
}
}
struct sde_mdp_mixer *sde_mdp_mixer_get(struct sde_mdp_ctl *ctl, int mux)
{
struct sde_mdp_mixer *mixer = NULL;
if (!ctl) {
SDEROT_ERR("ctl not initialized\n");
return NULL;
}
switch (mux) {
case SDE_MDP_MIXER_MUX_DEFAULT:
case SDE_MDP_MIXER_MUX_LEFT:
mixer = ctl->mixer_left;
break;
case SDE_MDP_MIXER_MUX_RIGHT:
mixer = ctl->mixer_right;
break;
}
return mixer;
}
int sde_mdp_get_pipe_flush_bits(struct sde_mdp_pipe *pipe)
{
u32 flush_bits = 0;
if (pipe->type == SDE_MDP_PIPE_TYPE_DMA)
flush_bits |= BIT(pipe->num) << 5;
else if (pipe->num == SDE_MDP_SSPP_VIG3 ||
pipe->num == SDE_MDP_SSPP_RGB3)
flush_bits |= BIT(pipe->num) << 10;
else if (pipe->type == SDE_MDP_PIPE_TYPE_CURSOR)
flush_bits |= BIT(22 + pipe->num - SDE_MDP_SSPP_CURSOR0);
else /* RGB/VIG 0-2 pipes */
flush_bits |= BIT(pipe->num);
return flush_bits;
}
int sde_mdp_mixer_pipe_update(struct sde_mdp_pipe *pipe,
struct sde_mdp_mixer *mixer, int params_changed)
{
struct sde_mdp_ctl *ctl;
if (!pipe)
return -EINVAL;
if (!mixer)
return -EINVAL;
ctl = mixer->ctl;
if (!ctl)
return -EINVAL;
ctl->flush_bits |= sde_mdp_get_pipe_flush_bits(pipe);
return 0;
}
int sde_mdp_display_wait4comp(struct sde_mdp_ctl *ctl)
{
int ret = 0;
if (!ctl) {
SDEROT_ERR("invalid ctl\n");
return -ENODEV;
}
if (ctl->ops.wait_fnc)
ret = ctl->ops.wait_fnc(ctl, NULL);
return ret;
}
int sde_mdp_display_commit(struct sde_mdp_ctl *ctl, void *arg,
struct sde_mdp_commit_cb *commit_cb)
{
int ret = 0;
u32 ctl_flush_bits = 0;
if (!ctl) {
SDEROT_ERR("display function not set\n");
return -ENODEV;
}
if (ctl->ops.prepare_fnc)
ret = ctl->ops.prepare_fnc(ctl, arg);
if (ret) {
SDEROT_ERR("error preparing display\n");
goto done;
}
sde_mdp_mixer_setup(ctl, SDE_MDP_MIXER_MUX_LEFT);
sde_mdp_mixer_setup(ctl, SDE_MDP_MIXER_MUX_RIGHT);
sde_mdp_ctl_write(ctl, SDE_MDP_REG_CTL_TOP, ctl->opmode);
ctl->flush_bits |= BIT(17); /* CTL */
ctl_flush_bits = ctl->flush_bits;
sde_mdp_ctl_write(ctl, SDE_MDP_REG_CTL_FLUSH, ctl_flush_bits);
/* ensure the flush command is issued after the barrier */
wmb();
ctl->flush_reg_data = ctl_flush_bits;
ctl->flush_bits = 0;
if (ctl->ops.display_fnc)
ret = ctl->ops.display_fnc(ctl, arg); /* DSI0 kickoff */
if (ret)
SDEROT_WARN("ctl %d error displaying frame\n", ctl->num);
done:
return ret;
}
/**
* @sde_mdp_ctl_mixer_switch() - return ctl mixer of @return_type
* @ctl: Pointer to ctl structure to be switched.
* @return_type: wb_type of the ctl to be switched to.
*
* Virtual mixer switch should be performed only when there is no
* dedicated wfd block and writeback block is shared.
*/
struct sde_mdp_ctl *sde_mdp_ctl_mixer_switch(struct sde_mdp_ctl *ctl,
u32 return_type)
{
if (ctl->wb_type == return_type)
return ctl;
SDEROT_ERR("unable to switch mixer to type=%d\n", return_type);
return NULL;
}
struct sde_mdp_writeback *sde_mdp_wb_assign(u32 num, u32 reg_index)
{
struct sde_rot_data_type *mdata = sde_rot_get_mdata();
struct sde_mdp_writeback *wb = NULL;
static struct sde_mdp_writeback sde_wb[16];
static const u32 offset[] = {0x00065000, 0x00065800, 0x00066000};
if (num >= ARRAY_SIZE(offset)) {
SDEROT_ERR("invalid parameters\n");
return ERR_PTR(-EINVAL);
}
wb = &sde_wb[num];
wb->num = num;
wb->offset = offset[wb->num];
if (!wb)
return NULL;
wb->base = mdata->sde_io.base;
wb->base += wb->offset;
return wb;
}
void sde_mdp_wb_free(struct sde_mdp_writeback *wb)
{
}