Revert "drm/msm/sde: sde encoder virtualization"
This reverts 'commit a142ec80ca
("drm/msm/sde: sde
encoder virtualization")'
This is partial change for display drm driver,
that will break drm/sde merge commit.
Change-Id: Ida1e127788961e1c9484b0a69695d0ad5391cf88
Signed-off-by: Narendra Muppalla <NarendraM@codeaurora.org>
This commit is contained in:
parent
d85ef1552e
commit
ab0bad483d
5 changed files with 285 additions and 622 deletions
|
@ -40,8 +40,6 @@ msm-y := \
|
|||
mdp/mdp5/mdp5_smp.o \
|
||||
sde/sde_crtc.o \
|
||||
sde/sde_encoder.o \
|
||||
sde/sde_encoder_phys_vid.o \
|
||||
sde/sde_encoder_phys_cmd.o \
|
||||
sde/sde_irq.o \
|
||||
sde/sde_kms.o \
|
||||
sde/sde_plane.o \
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "msm_drv.h"
|
||||
#include "sde_kms.h"
|
||||
#include "drm_crtc.h"
|
||||
#include "drm_crtc_helper.h"
|
||||
|
@ -21,11 +20,32 @@
|
|||
#include "sde_hw_mdp_ctl.h"
|
||||
#include "sde_mdp_formats.h"
|
||||
|
||||
#include "sde_encoder_phys.h"
|
||||
|
||||
#include "../dsi-staging/dsi_display.h"
|
||||
|
||||
#define to_sde_encoder_virt(x) container_of(x, struct sde_encoder_virt, base)
|
||||
#define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__)
|
||||
|
||||
struct sde_encoder {
|
||||
struct drm_encoder base;
|
||||
spinlock_t intf_lock;
|
||||
bool enabled;
|
||||
uint32_t bus_scaling_client;
|
||||
struct sde_hw_intf *hw_intf;
|
||||
struct sde_hw_ctl *hw_ctl;
|
||||
int drm_mode_enc;
|
||||
|
||||
void (*vblank_callback)(void *);
|
||||
void *vblank_callback_data;
|
||||
|
||||
struct mdp_irq vblank_irq;
|
||||
};
|
||||
#define to_sde_encoder(x) container_of(x, struct sde_encoder, base)
|
||||
|
||||
static struct sde_kms *get_kms(struct drm_encoder *drm_enc)
|
||||
{
|
||||
struct msm_drm_private *priv = drm_enc->dev->dev_private;
|
||||
|
||||
return to_sde_kms(to_mdp_kms(priv->kms));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_QCOM_BUS_SCALING
|
||||
#include <linux/msm-bus.h>
|
||||
|
@ -42,7 +62,6 @@ static struct msm_bus_vectors mdp_bus_vectors[] = {
|
|||
MDP_BUS_VECTOR_ENTRY(0, 0),
|
||||
MDP_BUS_VECTOR_ENTRY(2000000000, 2000000000),
|
||||
};
|
||||
|
||||
static struct msm_bus_paths mdp_bus_usecases[] = { {
|
||||
.num_paths = 1,
|
||||
.vectors =
|
||||
|
@ -60,14 +79,14 @@ static struct msm_bus_scale_pdata mdp_bus_scale_table = {
|
|||
.name = "mdss_mdp",
|
||||
};
|
||||
|
||||
static void bs_init(struct sde_encoder_virt *sde_enc)
|
||||
static void bs_init(struct sde_encoder *sde_enc)
|
||||
{
|
||||
sde_enc->bus_scaling_client =
|
||||
msm_bus_scale_register_client(&mdp_bus_scale_table);
|
||||
DBG("bus scale client: %08x", sde_enc->bus_scaling_client);
|
||||
}
|
||||
|
||||
static void bs_fini(struct sde_encoder_virt *sde_enc)
|
||||
static void bs_fini(struct sde_encoder *sde_enc)
|
||||
{
|
||||
if (sde_enc->bus_scaling_client) {
|
||||
msm_bus_scale_unregister_client(sde_enc->bus_scaling_client);
|
||||
|
@ -75,7 +94,7 @@ static void bs_fini(struct sde_encoder_virt *sde_enc)
|
|||
}
|
||||
}
|
||||
|
||||
static void bs_set(struct sde_encoder_virt *sde_enc, int idx)
|
||||
static void bs_set(struct sde_encoder *sde_enc, int idx)
|
||||
{
|
||||
if (sde_enc->bus_scaling_client) {
|
||||
DBG("set bus scaling: %d", idx);
|
||||
|
@ -85,189 +104,242 @@ static void bs_set(struct sde_encoder_virt *sde_enc, int idx)
|
|||
}
|
||||
}
|
||||
#else
|
||||
static void bs_init(struct sde_encoder_virt *sde_enc)
|
||||
static void bs_init(struct sde_encoder *sde_enc)
|
||||
{
|
||||
}
|
||||
|
||||
static void bs_fini(struct sde_encoder_virt *sde_enc)
|
||||
static void bs_fini(struct sde_encoder *sde_enc)
|
||||
{
|
||||
}
|
||||
|
||||
static void bs_set(struct sde_encoder_virt *sde_enc, int idx)
|
||||
static void bs_set(struct sde_encoder *sde_enc, int idx)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
void sde_encoder_get_hw_resources(struct drm_encoder *drm_enc,
|
||||
struct sde_encoder_hw_resources *hw_res)
|
||||
static bool sde_encoder_mode_fixup(struct drm_encoder *drm_enc,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
|
||||
int i = 0;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (!hw_res) {
|
||||
DRM_ERROR("Invalid pointer");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Query resources used by phys encs, expected to be without overlap */
|
||||
memset(hw_res, 0, sizeof(*hw_res));
|
||||
for (i = 0; i < sde_enc->num_phys_encs; i++) {
|
||||
struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
|
||||
|
||||
if (phys)
|
||||
phys->phys_ops.get_hw_resources(phys, hw_res);
|
||||
}
|
||||
}
|
||||
|
||||
static void sde_encoder_destroy(struct drm_encoder *drm_enc)
|
||||
{
|
||||
struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
|
||||
int i = 0;
|
||||
|
||||
DBG("");
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sde_enc->phys_encs); i++) {
|
||||
struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
|
||||
|
||||
if (phys) {
|
||||
phys->phys_ops.destroy(phys);
|
||||
--sde_enc->num_phys_encs;
|
||||
sde_enc->phys_encs[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (sde_enc->num_phys_encs) {
|
||||
DRM_ERROR("Expected num_phys_encs to be 0 not %d\n",
|
||||
sde_enc->num_phys_encs);
|
||||
}
|
||||
|
||||
drm_encoder_cleanup(drm_enc);
|
||||
bs_fini(sde_enc);
|
||||
kfree(sde_enc);
|
||||
}
|
||||
|
||||
static bool sde_encoder_virt_mode_fixup(struct drm_encoder *drm_enc,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
|
||||
int i = 0;
|
||||
|
||||
DBG("");
|
||||
|
||||
for (i = 0; i < sde_enc->num_phys_encs; i++) {
|
||||
struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
|
||||
|
||||
if (phys) {
|
||||
phys->phys_ops.mode_fixup(phys, mode, adjusted_mode);
|
||||
if (memcmp(mode, adjusted_mode, sizeof(*mode)) != 0) {
|
||||
DRM_ERROR("adjusted modes not supported\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void sde_encoder_virt_mode_set(struct drm_encoder *drm_enc,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
static void sde_encoder_mode_set(struct drm_encoder *drm_enc,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
|
||||
int i = 0;
|
||||
|
||||
DBG("");
|
||||
struct sde_encoder *sde_enc = to_sde_encoder(drm_enc);
|
||||
struct intf_timing_params p = {0};
|
||||
uint32_t hsync_polarity = 0, vsync_polarity = 0;
|
||||
struct sde_mdp_format_params *sde_fmt_params = NULL;
|
||||
u32 fmt_fourcc = DRM_FORMAT_RGB888, fmt_mod = 0;
|
||||
unsigned long lock_flags;
|
||||
struct sde_hw_intf_cfg intf_cfg = {0};
|
||||
|
||||
for (i = 0; i < sde_enc->num_phys_encs; i++) {
|
||||
struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
|
||||
mode = adjusted_mode;
|
||||
|
||||
if (phys) {
|
||||
phys->phys_ops.mode_set(phys, mode, adjusted_mode);
|
||||
if (memcmp(mode, adjusted_mode, sizeof(*mode)) != 0)
|
||||
DRM_ERROR("adjusted modes not supported\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
|
||||
mode->base.id, mode->name, mode->vrefresh, mode->clock,
|
||||
mode->hdisplay, mode->hsync_start, mode->hsync_end, mode->htotal,
|
||||
mode->vdisplay, mode->vsync_start, mode->vsync_end, mode->vtotal,
|
||||
mode->type, mode->flags);
|
||||
|
||||
static void sde_encoder_virt_enable(struct drm_encoder *drm_enc)
|
||||
{
|
||||
struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
|
||||
int i = 0;
|
||||
|
||||
DBG("");
|
||||
|
||||
bs_set(sde_enc, 1);
|
||||
|
||||
for (i = 0; i < sde_enc->num_phys_encs; i++) {
|
||||
struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
|
||||
|
||||
if (phys)
|
||||
phys->phys_ops.enable(phys);
|
||||
}
|
||||
}
|
||||
|
||||
static void sde_encoder_virt_disable(struct drm_encoder *drm_enc)
|
||||
{
|
||||
struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
|
||||
int i = 0;
|
||||
|
||||
DBG("");
|
||||
|
||||
for (i = 0; i < sde_enc->num_phys_encs; i++) {
|
||||
struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
|
||||
|
||||
if (phys && phys->phys_ops.disable)
|
||||
phys->phys_ops.disable(phys);
|
||||
/* DSI controller cannot handle active-low sync signals. */
|
||||
if (sde_enc->hw_intf->cap->type != INTF_DSI) {
|
||||
if (mode->flags & DRM_MODE_FLAG_NHSYNC)
|
||||
hsync_polarity = 1;
|
||||
if (mode->flags & DRM_MODE_FLAG_NVSYNC)
|
||||
vsync_polarity = 1;
|
||||
}
|
||||
|
||||
bs_set(sde_enc, 0);
|
||||
/*
|
||||
* For edp only:
|
||||
* DISPLAY_V_START = (VBP * HCYCLE) + HBP
|
||||
* DISPLAY_V_END = (VBP + VACTIVE) * HCYCLE - 1 - HFP
|
||||
*/
|
||||
/*
|
||||
* if (sde_enc->hw->cap->type == INTF_EDP) {
|
||||
* display_v_start += mode->htotal - mode->hsync_start;
|
||||
* display_v_end -= mode->hsync_start - mode->hdisplay;
|
||||
* }
|
||||
*/
|
||||
|
||||
/*
|
||||
* https://www.kernel.org/doc/htmldocs/drm/ch02s05.html
|
||||
* Active Region Front Porch Sync Back Porch
|
||||
* <---------------------><----------------><---------><-------------->
|
||||
* <--- [hv]display ----->
|
||||
* <----------- [hv]sync_start ------------>
|
||||
* <------------------- [hv]sync_end ----------------->
|
||||
* <------------------------------ [hv]total ------------------------->
|
||||
*/
|
||||
|
||||
sde_fmt_params = sde_mdp_get_format_params(fmt_fourcc, fmt_mod);
|
||||
|
||||
p.width = mode->hdisplay; /* active width */
|
||||
p.height = mode->vdisplay; /* active height */
|
||||
p.xres = p.width; /* Display panel width */
|
||||
p.yres = p.height; /* Display panel height */
|
||||
p.h_back_porch = mode->htotal - mode->hsync_end;
|
||||
p.h_front_porch = mode->hsync_start - mode->hdisplay;
|
||||
p.v_back_porch = mode->vtotal - mode->vsync_end;
|
||||
p.v_front_porch = mode->vsync_start - mode->vdisplay;
|
||||
p.hsync_pulse_width = mode->hsync_end - mode->hsync_start;
|
||||
p.vsync_pulse_width = mode->vsync_end - mode->vsync_start;
|
||||
p.hsync_polarity = hsync_polarity;
|
||||
p.vsync_polarity = vsync_polarity;
|
||||
p.border_clr = 0;
|
||||
p.underflow_clr = 0xff;
|
||||
p.hsync_skew = mode->hskew;
|
||||
|
||||
intf_cfg.intf = sde_enc->hw_intf->idx;
|
||||
intf_cfg.wb = SDE_NONE;
|
||||
|
||||
spin_lock_irqsave(&sde_enc->intf_lock, lock_flags);
|
||||
sde_enc->hw_intf->ops.setup_timing_gen(sde_enc->hw_intf, &p,
|
||||
sde_fmt_params);
|
||||
sde_enc->hw_ctl->ops.setup_intf_cfg(sde_enc->hw_ctl, &intf_cfg);
|
||||
spin_unlock_irqrestore(&sde_enc->intf_lock, lock_flags);
|
||||
}
|
||||
|
||||
static const struct drm_encoder_helper_funcs sde_encoder_helper_funcs = {
|
||||
.mode_fixup = sde_encoder_virt_mode_fixup,
|
||||
.mode_set = sde_encoder_virt_mode_set,
|
||||
.disable = sde_encoder_virt_disable,
|
||||
.enable = sde_encoder_virt_enable,
|
||||
};
|
||||
|
||||
static const struct drm_encoder_funcs sde_encoder_funcs = {
|
||||
.destroy = sde_encoder_destroy,
|
||||
};
|
||||
|
||||
static enum sde_intf sde_encoder_get_intf(struct sde_mdss_cfg *catalog,
|
||||
enum sde_intf_type type, u32 instance)
|
||||
static void sde_encoder_wait_for_vblank(struct sde_encoder *sde_enc)
|
||||
{
|
||||
int i = 0;
|
||||
struct sde_kms *sde_kms = get_kms(&sde_enc->base);
|
||||
struct mdp_kms *mdp_kms = &sde_kms->base;
|
||||
|
||||
DBG("");
|
||||
|
||||
for (i = 0; i < catalog->intf_count; i++) {
|
||||
if (catalog->intf[i].type == type
|
||||
&& catalog->intf[i].controller_id == instance) {
|
||||
return catalog->intf[i].id;
|
||||
}
|
||||
}
|
||||
|
||||
return INTF_MAX;
|
||||
mdp_irq_wait(mdp_kms, sde_enc->vblank_irq.irqmask);
|
||||
}
|
||||
|
||||
static void sde_encoder_vblank_callback(struct drm_encoder *drm_enc)
|
||||
static void sde_encoder_vblank_irq(struct mdp_irq *irq, uint32_t irqstatus)
|
||||
{
|
||||
struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
|
||||
struct sde_encoder *sde_enc = container_of(irq, struct sde_encoder,
|
||||
vblank_irq);
|
||||
struct intf_status status = { 0 };
|
||||
unsigned long lock_flags;
|
||||
|
||||
spin_lock_irqsave(&sde_enc->intf_lock, lock_flags);
|
||||
if (sde_enc->vblank_callback)
|
||||
sde_enc->vblank_callback(sde_enc->vblank_callback_data);
|
||||
spin_unlock_irqrestore(&sde_enc->intf_lock, lock_flags);
|
||||
|
||||
sde_enc->hw_intf->ops.get_status(sde_enc->hw_intf, &status);
|
||||
}
|
||||
|
||||
static void sde_encoder_disable(struct drm_encoder *drm_enc)
|
||||
{
|
||||
struct sde_encoder *sde_enc = to_sde_encoder(drm_enc);
|
||||
struct sde_kms *sde_kms = get_kms(drm_enc);
|
||||
struct mdp_kms *mdp_kms = &(sde_kms->base);
|
||||
unsigned long lock_flags;
|
||||
|
||||
DBG("");
|
||||
|
||||
spin_lock_irqsave(&sde_enc->spin_lock, lock_flags);
|
||||
if (sde_enc->kms_vblank_callback)
|
||||
sde_enc->kms_vblank_callback(sde_enc->kms_vblank_callback_data);
|
||||
spin_unlock_irqrestore(&sde_enc->spin_lock, lock_flags);
|
||||
if (WARN_ON(!sde_enc->enabled))
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&sde_enc->intf_lock, lock_flags);
|
||||
sde_enc->hw_intf->ops.enable_timing(sde_enc->hw_intf, 0);
|
||||
spin_unlock_irqrestore(&sde_enc->intf_lock, lock_flags);
|
||||
|
||||
/*
|
||||
* Wait for a vsync so we know the ENABLE=0 latched before
|
||||
* the (connector) source of the vsync's gets disabled,
|
||||
* otherwise we end up in a funny state if we re-enable
|
||||
* before the disable latches, which results that some of
|
||||
* the settings changes for the new modeset (like new
|
||||
* scanout buffer) don't latch properly..
|
||||
*/
|
||||
sde_encoder_wait_for_vblank(sde_enc);
|
||||
|
||||
mdp_irq_unregister(mdp_kms, &sde_enc->vblank_irq);
|
||||
bs_set(sde_enc, 0);
|
||||
sde_enc->enabled = false;
|
||||
}
|
||||
|
||||
static int sde_encoder_virt_add_phys_vid_enc(struct sde_encoder_virt *sde_enc,
|
||||
static void sde_encoder_enable(struct drm_encoder *drm_enc)
|
||||
{
|
||||
struct sde_encoder *sde_enc = to_sde_encoder(drm_enc);
|
||||
struct mdp_kms *mdp_kms = &(get_kms(drm_enc)->base);
|
||||
unsigned long lock_flags;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (WARN_ON(sde_enc->enabled))
|
||||
return;
|
||||
|
||||
bs_set(sde_enc, 1);
|
||||
spin_lock_irqsave(&sde_enc->intf_lock, lock_flags);
|
||||
sde_enc->hw_intf->ops.enable_timing(sde_enc->hw_intf, 1);
|
||||
spin_unlock_irqrestore(&sde_enc->intf_lock, lock_flags);
|
||||
sde_enc->enabled = true;
|
||||
|
||||
mdp_irq_register(mdp_kms, &sde_enc->vblank_irq);
|
||||
DBG("Registered IRQ for intf %d mask 0x%X", sde_enc->hw_intf->idx,
|
||||
sde_enc->vblank_irq.irqmask);
|
||||
}
|
||||
|
||||
void sde_encoder_get_hw_resources(struct drm_encoder *drm_enc,
|
||||
struct sde_encoder_hw_resources *hw_res)
|
||||
{
|
||||
struct sde_encoder *sde_enc = to_sde_encoder(drm_enc);
|
||||
|
||||
DBG("");
|
||||
|
||||
if (WARN_ON(!hw_res))
|
||||
return;
|
||||
|
||||
memset(hw_res, 0, sizeof(*hw_res));
|
||||
hw_res->intfs[sde_enc->hw_intf->idx] = true;
|
||||
}
|
||||
|
||||
static void sde_encoder_destroy(struct drm_encoder *drm_enc)
|
||||
{
|
||||
struct sde_encoder *sde_enc = to_sde_encoder(drm_enc);
|
||||
|
||||
DBG("");
|
||||
drm_encoder_cleanup(drm_enc);
|
||||
bs_fini(sde_enc);
|
||||
kfree(sde_enc->hw_intf);
|
||||
kfree(sde_enc);
|
||||
}
|
||||
|
||||
static const struct drm_encoder_helper_funcs sde_encoder_helper_funcs = {
|
||||
.mode_fixup = sde_encoder_mode_fixup,
|
||||
.mode_set = sde_encoder_mode_set,
|
||||
.disable = sde_encoder_disable,
|
||||
.enable = sde_encoder_enable,
|
||||
};
|
||||
|
||||
static const struct drm_encoder_funcs sde_encoder_funcs = {.destroy =
|
||||
sde_encoder_destroy,
|
||||
};
|
||||
|
||||
static int sde_encoder_setup_hw(struct sde_encoder *sde_enc,
|
||||
struct sde_kms *sde_kms,
|
||||
enum sde_intf intf_idx,
|
||||
enum sde_ctl ctl_idx)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
DBG("");
|
||||
|
||||
sde_enc->hw_intf = sde_hw_intf_init(intf_idx, sde_kms->mmio,
|
||||
sde_kms->catalog);
|
||||
if (!sde_enc->hw_intf)
|
||||
return -EINVAL;
|
||||
|
||||
sde_enc->hw_ctl = sde_hw_ctl_init(ctl_idx, sde_kms->mmio,
|
||||
sde_kms->catalog);
|
||||
if (!sde_enc->hw_ctl)
|
||||
return -EINVAL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sde_encoder_virt_add_phys_vid_enc(struct sde_encoder *sde_enc,
|
||||
struct sde_kms *sde_kms,
|
||||
enum sde_intf intf_idx,
|
||||
enum sde_ctl ctl_idx)
|
||||
|
@ -276,30 +348,15 @@ static int sde_encoder_virt_add_phys_vid_enc(struct sde_encoder_virt *sde_enc,
|
|||
|
||||
DBG("");
|
||||
|
||||
if (sde_enc->num_phys_encs >= ARRAY_SIZE(sde_enc->phys_encs)) {
|
||||
DRM_ERROR("Too many video encoders %d, unable to add\n",
|
||||
sde_enc->num_phys_encs);
|
||||
ret = -EINVAL;
|
||||
} else {
|
||||
struct sde_encoder_virt_ops parent_ops = {
|
||||
sde_encoder_vblank_callback
|
||||
};
|
||||
struct sde_encoder_phys *enc =
|
||||
sde_encoder_phys_vid_init(sde_kms, intf_idx, ctl_idx,
|
||||
&sde_enc->base, parent_ops);
|
||||
if (IS_ERR(enc))
|
||||
ret = PTR_ERR(enc);
|
||||
|
||||
if (!ret) {
|
||||
sde_enc->phys_encs[sde_enc->num_phys_encs] = enc;
|
||||
++sde_enc->num_phys_encs;
|
||||
}
|
||||
ret = sde_encoder_setup_hw(sde_enc, sde_kms, intf_idx, ctl_idx);
|
||||
if (!ret) {
|
||||
sde_enc->vblank_irq.irq = sde_encoder_vblank_irq;
|
||||
sde_enc->vblank_irq.irqmask = 0x8000000;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sde_encoder_setup_hdmi(struct sde_encoder_virt *sde_enc,
|
||||
static int sde_encoder_setup_hdmi(struct sde_encoder *sde_enc,
|
||||
struct sde_kms *sde_kms, int *hdmi_info)
|
||||
{
|
||||
int ret = 0;
|
||||
|
@ -307,7 +364,9 @@ static int sde_encoder_setup_hdmi(struct sde_encoder_virt *sde_enc,
|
|||
|
||||
DBG("");
|
||||
|
||||
intf_idx = sde_encoder_get_intf(sde_kms->catalog, INTF_HDMI, 0);
|
||||
sde_enc->drm_mode_enc = DRM_MODE_ENCODER_TMDS;
|
||||
|
||||
intf_idx = INTF_3;
|
||||
if (intf_idx == INTF_MAX)
|
||||
ret = -EINVAL;
|
||||
|
||||
|
@ -320,7 +379,7 @@ static int sde_encoder_setup_hdmi(struct sde_encoder_virt *sde_enc,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int sde_encoder_setup_dsi(struct sde_encoder_virt *sde_enc,
|
||||
static int sde_encoder_setup_dsi(struct sde_encoder *sde_enc,
|
||||
struct sde_kms *sde_kms,
|
||||
struct dsi_display_info *dsi_info)
|
||||
{
|
||||
|
@ -329,27 +388,30 @@ static int sde_encoder_setup_dsi(struct sde_encoder_virt *sde_enc,
|
|||
|
||||
DBG("");
|
||||
|
||||
WARN_ON(dsi_info->num_of_h_tiles < 1);
|
||||
sde_enc->drm_mode_enc = DRM_MODE_ENCODER_DSI;
|
||||
|
||||
if (dsi_info->num_of_h_tiles == 0)
|
||||
dsi_info->num_of_h_tiles = 1;
|
||||
if (WARN_ON(dsi_info->num_of_h_tiles > 1)) {
|
||||
DBG("Dual DSI mode not yet supported");
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
WARN_ON(dsi_info->num_of_h_tiles != 1);
|
||||
dsi_info->num_of_h_tiles = 1;
|
||||
|
||||
DBG("dsi_info->num_of_h_tiles %d h_tiled %d dsi_info->h_tile_ids %d ",
|
||||
dsi_info->num_of_h_tiles, dsi_info->h_tiled,
|
||||
dsi_info->h_tile_ids[0]);
|
||||
dsi_info->num_of_h_tiles, dsi_info->h_tiled,
|
||||
dsi_info->h_tile_ids[0]);
|
||||
|
||||
for (i = 0; i < dsi_info->num_of_h_tiles && !ret; i++) {
|
||||
enum sde_intf intf_idx = INTF_MAX;
|
||||
for (i = 0; i < !ret && dsi_info->num_of_h_tiles; i++) {
|
||||
enum sde_intf intf_idx = INTF_1;
|
||||
enum sde_ctl ctl_idx = CTL_0;
|
||||
|
||||
intf_idx = sde_encoder_get_intf(sde_kms->catalog,
|
||||
INTF_DSI, dsi_info->h_tile_ids[i]);
|
||||
if (intf_idx == INTF_MAX) {
|
||||
DBG("Error: could not get the interface id");
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
/* Create both VID and CMD Phys Encoders here */
|
||||
/* Get DSI modes, create both VID & CMD Phys Encoders */
|
||||
if (!ret)
|
||||
ret =
|
||||
sde_encoder_virt_add_phys_vid_enc(sde_enc, sde_kms,
|
||||
|
@ -367,13 +429,13 @@ struct display_probe_info {
|
|||
};
|
||||
|
||||
static struct drm_encoder *sde_encoder_virt_init(struct drm_device *dev,
|
||||
struct display_probe_info *display)
|
||||
struct display_probe_info
|
||||
*display)
|
||||
{
|
||||
struct msm_drm_private *priv = dev->dev_private;
|
||||
struct sde_kms *sde_kms = to_sde_kms(to_mdp_kms(priv->kms));
|
||||
struct drm_encoder *drm_enc = NULL;
|
||||
struct sde_encoder_virt *sde_enc = NULL;
|
||||
int drm_encoder_mode = DRM_MODE_ENCODER_NONE;
|
||||
struct sde_encoder *sde_enc = NULL;
|
||||
int ret = 0;
|
||||
|
||||
DBG("");
|
||||
|
@ -385,35 +447,31 @@ static struct drm_encoder *sde_encoder_virt_init(struct drm_device *dev,
|
|||
}
|
||||
|
||||
if (display->type == INTF_DSI) {
|
||||
drm_encoder_mode = DRM_MODE_ENCODER_DSI;
|
||||
ret =
|
||||
sde_encoder_setup_dsi(sde_enc, sde_kms, &display->dsi_info);
|
||||
|
||||
} else if (display->type == INTF_HDMI) {
|
||||
drm_encoder_mode = DRM_MODE_ENCODER_TMDS;
|
||||
ret =
|
||||
sde_encoder_setup_hdmi(sde_enc, sde_kms,
|
||||
&display->hdmi_info);
|
||||
} else {
|
||||
DRM_ERROR("No valid displays found\n");
|
||||
DBG("No valid displays found");
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
spin_lock_init(&sde_enc->spin_lock);
|
||||
spin_lock_init(&sde_enc->intf_lock);
|
||||
drm_enc = &sde_enc->base;
|
||||
drm_encoder_init(dev, drm_enc, &sde_encoder_funcs, drm_encoder_mode);
|
||||
drm_encoder_init(dev, drm_enc, &sde_encoder_funcs,
|
||||
sde_enc->drm_mode_enc);
|
||||
drm_encoder_helper_add(drm_enc, &sde_encoder_helper_funcs);
|
||||
bs_init(sde_enc);
|
||||
|
||||
DBG("Created encoder");
|
||||
DBG("Created sde_encoder for intf %d", sde_enc->hw_intf->idx);
|
||||
|
||||
return drm_enc;
|
||||
|
||||
fail:
|
||||
DRM_ERROR("Failed to create encoder\n");
|
||||
if (drm_enc)
|
||||
sde_encoder_destroy(drm_enc);
|
||||
|
||||
|
@ -434,12 +492,10 @@ static int sde_encoder_probe_hdmi(struct drm_device *dev)
|
|||
enc = sde_encoder_virt_init(dev, &probe_info);
|
||||
if (IS_ERR(enc))
|
||||
ret = PTR_ERR(enc);
|
||||
|
||||
if (!ret) {
|
||||
/* Register new encoder with the upper layer */
|
||||
else {
|
||||
/* Register new encoder with the upper layer */
|
||||
priv->encoders[priv->num_encoders++] = enc;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -454,56 +510,50 @@ static int sde_encoder_probe_dsi(struct drm_device *dev)
|
|||
|
||||
num_displays = dsi_display_get_num_of_displays();
|
||||
DBG("num_displays %d", num_displays);
|
||||
|
||||
if (priv->num_encoders + num_displays > ARRAY_SIZE(priv->encoders)) {
|
||||
DBG("Too many displays found in probe");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_displays; i++) {
|
||||
|
||||
struct dsi_display *dsi = dsi_display_get_display_by_index(i);
|
||||
|
||||
if (dsi_display_is_active(dsi)) {
|
||||
struct drm_encoder *enc = NULL;
|
||||
struct display_probe_info probe_info = { 0 };
|
||||
|
||||
DBG("display %d/%d is active", i, num_displays);
|
||||
probe_info.type = INTF_DSI;
|
||||
|
||||
DBG("display %d is active", i);
|
||||
|
||||
ret = dsi_display_get_info(dsi, &probe_info.dsi_info);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (WARN_ON(ret))
|
||||
DBG("Failed to retrieve dsi panel info");
|
||||
else {
|
||||
struct drm_encoder *enc =
|
||||
sde_encoder_virt_init(dev,
|
||||
&probe_info);
|
||||
if (IS_ERR(enc))
|
||||
return PTR_ERR(enc);
|
||||
|
||||
enc = sde_encoder_virt_init(dev, &probe_info);
|
||||
if (IS_ERR(enc))
|
||||
return PTR_ERR(enc);
|
||||
ret = dsi_display_drm_init(dsi, enc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = dsi_display_drm_init(dsi, enc);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Register new encoder with the upper layer */
|
||||
priv->encoders[priv->num_encoders++] = enc;
|
||||
}
|
||||
/* Register new encoder with the upper layer */
|
||||
priv->encoders[priv->num_encoders++] = enc;
|
||||
}
|
||||
} else
|
||||
DBG("display %d/%d is not active", i, num_displays);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void sde_encoder_register_vblank_callback(struct drm_encoder *drm_enc,
|
||||
void (*cb)(void *), void *data)
|
||||
{
|
||||
struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
|
||||
void (*cb)(void *), void *data) {
|
||||
struct sde_encoder *sde_enc = to_sde_encoder(drm_enc);
|
||||
unsigned long lock_flags;
|
||||
|
||||
DBG("");
|
||||
|
||||
spin_lock_irqsave(&sde_enc->spin_lock, lock_flags);
|
||||
sde_enc->kms_vblank_callback = cb;
|
||||
sde_enc->kms_vblank_callback_data = data;
|
||||
spin_unlock_irqrestore(&sde_enc->spin_lock, lock_flags);
|
||||
spin_lock_irqsave(&sde_enc->intf_lock, lock_flags);
|
||||
sde_enc->vblank_callback = cb;
|
||||
sde_enc->vblank_callback_data = data;
|
||||
spin_unlock_irqrestore(&sde_enc->intf_lock, lock_flags);
|
||||
}
|
||||
|
||||
/* encoders init,
|
||||
|
@ -516,14 +566,14 @@ void sde_encoders_init(struct drm_device *dev)
|
|||
|
||||
DBG("");
|
||||
|
||||
/* Start num_encoders at 0, probe functions will increment */
|
||||
/* Start num_encoders at 0, probe functions will increment */
|
||||
priv->num_encoders = 0;
|
||||
ret = sde_encoder_probe_dsi(dev);
|
||||
if (ret)
|
||||
DRM_ERROR("Error probing DSI, %d\n", ret);
|
||||
DBG("Error probing DSI, %d", ret);
|
||||
else {
|
||||
ret = sde_encoder_probe_hdmi(dev);
|
||||
if (ret)
|
||||
DRM_ERROR("Error probing HDMI, %d\n", ret);
|
||||
DBG("Error probing HDMI, %d", ret);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,80 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015 The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SDE_ENCODER_PHYS_H__
|
||||
#define __SDE_ENCODER_PHYS_H__
|
||||
|
||||
#include "sde_kms.h"
|
||||
#include "sde_hw_intf.h"
|
||||
#include "sde_hw_mdp_ctl.h"
|
||||
|
||||
#define MAX_PHYS_ENCODERS_PER_VIRTUAL 4
|
||||
|
||||
struct sde_encoder_phys;
|
||||
|
||||
struct sde_encoder_virt_ops {
|
||||
void (*handle_vblank_virt)(struct drm_encoder *);
|
||||
};
|
||||
|
||||
struct sde_encoder_phys_ops {
|
||||
void (*mode_set)(struct sde_encoder_phys *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode);
|
||||
bool (*mode_fixup)(struct sde_encoder_phys *encoder,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode);
|
||||
void (*enable)(struct sde_encoder_phys *encoder);
|
||||
void (*disable)(struct sde_encoder_phys *encoder);
|
||||
void (*destroy)(struct sde_encoder_phys *encoder);
|
||||
void (*get_hw_resources)(struct sde_encoder_phys *encoder,
|
||||
struct sde_encoder_hw_resources *hw_res);
|
||||
};
|
||||
|
||||
struct sde_encoder_phys {
|
||||
struct drm_encoder *parent;
|
||||
struct sde_encoder_virt_ops parent_ops;
|
||||
struct sde_encoder_phys_ops phys_ops;
|
||||
struct sde_hw_intf *hw_intf;
|
||||
struct sde_hw_ctl *hw_ctl;
|
||||
struct mdp_kms *mdp_kms;
|
||||
struct drm_display_mode cached_mode;
|
||||
bool enabled;
|
||||
spinlock_t spin_lock;
|
||||
};
|
||||
|
||||
struct sde_encoder_phys_vid {
|
||||
struct sde_encoder_phys base;
|
||||
struct mdp_irq vblank_irq;
|
||||
};
|
||||
|
||||
struct sde_encoder_virt {
|
||||
struct drm_encoder base;
|
||||
spinlock_t spin_lock;
|
||||
uint32_t bus_scaling_client;
|
||||
|
||||
int num_phys_encs;
|
||||
struct sde_encoder_phys *phys_encs[MAX_PHYS_ENCODERS_PER_VIRTUAL];
|
||||
|
||||
void (*kms_vblank_callback)(void *);
|
||||
void *kms_vblank_callback_data;
|
||||
};
|
||||
|
||||
struct sde_encoder_phys *sde_encoder_phys_vid_init(struct sde_kms *sde_kms,
|
||||
enum sde_intf intf_idx,
|
||||
enum sde_ctl ctl_idx,
|
||||
struct drm_encoder *parent,
|
||||
struct sde_encoder_virt_ops
|
||||
parent_ops);
|
||||
|
||||
#endif /* __sde_encoder_phys_H__ */
|
|
@ -1,25 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015 The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "msm_drv.h"
|
||||
#include "sde_kms.h"
|
||||
#include "drm_crtc.h"
|
||||
#include "drm_crtc_helper.h"
|
||||
|
||||
#include "sde_hwio.h"
|
||||
#include "sde_hw_catalog.h"
|
||||
#include "sde_hw_intf.h"
|
||||
#include "sde_mdp_formats.h"
|
||||
|
||||
#include "sde_encoder_phys.h"
|
|
@ -1,280 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015 The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "msm_drv.h"
|
||||
#include "sde_kms.h"
|
||||
#include "drm_crtc.h"
|
||||
#include "drm_crtc_helper.h"
|
||||
|
||||
#include "sde_encoder_phys.h"
|
||||
#include "sde_mdp_formats.h"
|
||||
|
||||
|
||||
#define to_sde_encoder_phys_vid(x) \
|
||||
container_of(x, struct sde_encoder_phys_vid, base)
|
||||
|
||||
static bool sde_encoder_phys_vid_mode_fixup(struct sde_encoder_phys *drm_enc,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode
|
||||
*adjusted_mode)
|
||||
{
|
||||
DBG("");
|
||||
return true;
|
||||
}
|
||||
|
||||
static void sde_encoder_phys_vid_mode_set(struct sde_encoder_phys *phys_enc,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode
|
||||
*adjusted_mode)
|
||||
{
|
||||
mode = adjusted_mode;
|
||||
phys_enc->cached_mode = *adjusted_mode;
|
||||
|
||||
DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
|
||||
mode->base.id, mode->name, mode->vrefresh, mode->clock,
|
||||
mode->hdisplay, mode->hsync_start, mode->hsync_end, mode->htotal,
|
||||
mode->vdisplay, mode->vsync_start, mode->vsync_end, mode->vtotal,
|
||||
mode->type, mode->flags);
|
||||
}
|
||||
|
||||
static void sde_encoder_phys_vid_setup_timing_engine(struct sde_encoder_phys
|
||||
*phys_enc)
|
||||
{
|
||||
struct drm_display_mode *mode = &phys_enc->cached_mode;
|
||||
struct intf_timing_params p = { 0 };
|
||||
uint32_t hsync_polarity = 0;
|
||||
uint32_t vsync_polarity = 0;
|
||||
struct sde_mdp_format_params *sde_fmt_params = NULL;
|
||||
u32 fmt_fourcc = DRM_FORMAT_RGB888;
|
||||
u32 fmt_mod = 0;
|
||||
unsigned long lock_flags;
|
||||
struct sde_hw_intf_cfg intf_cfg = {0};
|
||||
|
||||
DBG("enable mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
|
||||
mode->base.id, mode->name, mode->vrefresh, mode->clock,
|
||||
mode->hdisplay, mode->hsync_start, mode->hsync_end, mode->htotal,
|
||||
mode->vdisplay, mode->vsync_start, mode->vsync_end, mode->vtotal,
|
||||
mode->type, mode->flags);
|
||||
|
||||
/* DSI controller cannot handle active-low sync signals. */
|
||||
if (phys_enc->hw_intf->cap->type != INTF_DSI) {
|
||||
if (mode->flags & DRM_MODE_FLAG_NHSYNC)
|
||||
hsync_polarity = 1;
|
||||
if (mode->flags & DRM_MODE_FLAG_NVSYNC)
|
||||
vsync_polarity = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* For edp only:
|
||||
* DISPLAY_V_START = (VBP * HCYCLE) + HBP
|
||||
* DISPLAY_V_END = (VBP + VACTIVE) * HCYCLE - 1 - HFP
|
||||
*/
|
||||
/*
|
||||
* if (vid_enc->hw->cap->type == INTF_EDP) {
|
||||
* display_v_start += mode->htotal - mode->hsync_start;
|
||||
* display_v_end -= mode->hsync_start - mode->hdisplay;
|
||||
* }
|
||||
*/
|
||||
|
||||
/*
|
||||
* https://www.kernel.org/doc/htmldocs/drm/ch02s05.html
|
||||
* Active Region Front Porch Sync Back Porch
|
||||
* <---------------------><----------------><---------><-------------->
|
||||
* <--- [hv]display ----->
|
||||
* <----------- [hv]sync_start ------------>
|
||||
* <------------------- [hv]sync_end ----------------->
|
||||
* <------------------------------ [hv]total ------------------------->
|
||||
*/
|
||||
|
||||
sde_fmt_params = sde_mdp_get_format_params(fmt_fourcc, fmt_mod);
|
||||
|
||||
p.width = mode->hdisplay; /* active width */
|
||||
p.height = mode->vdisplay; /* active height */
|
||||
p.xres = p.width; /* Display panel width */
|
||||
p.yres = p.height; /* Display panel height */
|
||||
p.h_back_porch = mode->htotal - mode->hsync_end;
|
||||
p.h_front_porch = mode->hsync_start - mode->hdisplay;
|
||||
p.v_back_porch = mode->vtotal - mode->vsync_end;
|
||||
p.v_front_porch = mode->vsync_start - mode->vdisplay;
|
||||
p.hsync_pulse_width = mode->hsync_end - mode->hsync_start;
|
||||
p.vsync_pulse_width = mode->vsync_end - mode->vsync_start;
|
||||
p.hsync_polarity = hsync_polarity;
|
||||
p.vsync_polarity = vsync_polarity;
|
||||
p.border_clr = 0;
|
||||
p.underflow_clr = 0xff;
|
||||
p.hsync_skew = mode->hskew;
|
||||
|
||||
intf_cfg.intf = phys_enc->hw_intf->idx;
|
||||
intf_cfg.wb = SDE_NONE;
|
||||
|
||||
spin_lock_irqsave(&phys_enc->spin_lock, lock_flags);
|
||||
phys_enc->hw_intf->ops.setup_timing_gen(phys_enc->hw_intf, &p,
|
||||
sde_fmt_params);
|
||||
phys_enc->hw_ctl->ops.setup_intf_cfg(phys_enc->hw_ctl, &intf_cfg);
|
||||
spin_unlock_irqrestore(&phys_enc->spin_lock, lock_flags);
|
||||
}
|
||||
|
||||
static void sde_encoder_phys_vid_wait_for_vblank(struct sde_encoder_phys_vid
|
||||
*vid_enc)
|
||||
{
|
||||
DBG("");
|
||||
mdp_irq_wait(vid_enc->base.mdp_kms, vid_enc->vblank_irq.irqmask);
|
||||
}
|
||||
|
||||
static void sde_encoder_phys_vid_vblank_irq(struct mdp_irq *irq,
|
||||
uint32_t irqstatus)
|
||||
{
|
||||
struct sde_encoder_phys_vid *vid_enc =
|
||||
container_of(irq, struct sde_encoder_phys_vid,
|
||||
vblank_irq);
|
||||
struct sde_encoder_phys *phys_enc = &vid_enc->base;
|
||||
struct intf_status status = { 0 };
|
||||
|
||||
phys_enc->hw_intf->ops.get_status(phys_enc->hw_intf, &status);
|
||||
phys_enc->parent_ops.handle_vblank_virt(phys_enc->parent);
|
||||
}
|
||||
|
||||
static void sde_encoder_phys_vid_enable(struct sde_encoder_phys *phys_enc)
|
||||
{
|
||||
struct sde_encoder_phys_vid *vid_enc =
|
||||
to_sde_encoder_phys_vid(phys_enc);
|
||||
unsigned long lock_flags;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (WARN_ON(phys_enc->enabled))
|
||||
return;
|
||||
|
||||
sde_encoder_phys_vid_setup_timing_engine(phys_enc);
|
||||
|
||||
spin_lock_irqsave(&phys_enc->spin_lock, lock_flags);
|
||||
phys_enc->hw_intf->ops.enable_timing(phys_enc->hw_intf, 1);
|
||||
spin_unlock_irqrestore(&phys_enc->spin_lock, lock_flags);
|
||||
|
||||
phys_enc->enabled = true;
|
||||
|
||||
mdp_irq_register(phys_enc->mdp_kms, &vid_enc->vblank_irq);
|
||||
DBG("Registered IRQ for intf %d mask 0x%X", phys_enc->hw_intf->idx,
|
||||
vid_enc->vblank_irq.irqmask);
|
||||
}
|
||||
|
||||
static void sde_encoder_phys_vid_disable(struct sde_encoder_phys *phys_enc)
|
||||
{
|
||||
struct sde_encoder_phys_vid *vid_enc =
|
||||
to_sde_encoder_phys_vid(phys_enc);
|
||||
unsigned long lock_flags;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (WARN_ON(!phys_enc->enabled))
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&phys_enc->spin_lock, lock_flags);
|
||||
phys_enc->hw_intf->ops.enable_timing(phys_enc->hw_intf, 0);
|
||||
spin_unlock_irqrestore(&phys_enc->spin_lock, lock_flags);
|
||||
|
||||
/*
|
||||
* Wait for a vsync so we know the ENABLE=0 latched before
|
||||
* the (connector) source of the vsync's gets disabled,
|
||||
* otherwise we end up in a funny state if we re-enable
|
||||
* before the disable latches, which results that some of
|
||||
* the settings changes for the new modeset (like new
|
||||
* scanout buffer) don't latch properly..
|
||||
*/
|
||||
sde_encoder_phys_vid_wait_for_vblank(vid_enc);
|
||||
mdp_irq_unregister(phys_enc->mdp_kms, &vid_enc->vblank_irq);
|
||||
phys_enc->enabled = false;
|
||||
}
|
||||
|
||||
static void sde_encoder_phys_vid_destroy(struct sde_encoder_phys *phys_enc)
|
||||
{
|
||||
struct sde_encoder_phys_vid *vid_enc =
|
||||
to_sde_encoder_phys_vid(phys_enc);
|
||||
DBG("");
|
||||
kfree(phys_enc->hw_intf);
|
||||
kfree(vid_enc);
|
||||
}
|
||||
|
||||
static void sde_encoder_phys_vid_get_hw_resources(struct sde_encoder_phys
|
||||
*phys_enc, struct
|
||||
sde_encoder_hw_resources
|
||||
*hw_res)
|
||||
{
|
||||
DBG("");
|
||||
hw_res->intfs[phys_enc->hw_intf->idx] = true;
|
||||
}
|
||||
|
||||
static void sde_encoder_phys_vid_init_cbs(struct sde_encoder_phys_ops *ops)
|
||||
{
|
||||
ops->mode_set = sde_encoder_phys_vid_mode_set;
|
||||
ops->mode_fixup = sde_encoder_phys_vid_mode_fixup;
|
||||
ops->enable = sde_encoder_phys_vid_enable;
|
||||
ops->disable = sde_encoder_phys_vid_disable;
|
||||
ops->destroy = sde_encoder_phys_vid_destroy;
|
||||
ops->get_hw_resources = sde_encoder_phys_vid_get_hw_resources;
|
||||
}
|
||||
|
||||
struct sde_encoder_phys *sde_encoder_phys_vid_init(struct sde_kms *sde_kms,
|
||||
enum sde_intf intf_idx,
|
||||
enum sde_ctl ctl_idx,
|
||||
struct drm_encoder *parent,
|
||||
struct sde_encoder_virt_ops
|
||||
parent_ops)
|
||||
{
|
||||
struct sde_encoder_phys *phys_enc = NULL;
|
||||
struct sde_encoder_phys_vid *vid_enc = NULL;
|
||||
int ret = 0;
|
||||
|
||||
DBG("");
|
||||
|
||||
vid_enc = kzalloc(sizeof(*vid_enc), GFP_KERNEL);
|
||||
if (!vid_enc) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
phys_enc = &vid_enc->base;
|
||||
|
||||
phys_enc->hw_intf =
|
||||
sde_hw_intf_init(intf_idx, sde_kms->mmio, sde_kms->catalog);
|
||||
if (!phys_enc->hw_intf) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
phys_enc->hw_ctl = sde_hw_ctl_init(ctl_idx, sde_kms->mmio,
|
||||
sde_kms->catalog);
|
||||
if (!phys_enc->hw_ctl) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
sde_encoder_phys_vid_init_cbs(&phys_enc->phys_ops);
|
||||
phys_enc->parent = parent;
|
||||
phys_enc->parent_ops = parent_ops;
|
||||
phys_enc->mdp_kms = &sde_kms->base;
|
||||
vid_enc->vblank_irq.irq = sde_encoder_phys_vid_vblank_irq;
|
||||
vid_enc->vblank_irq.irqmask = 0x8000000;
|
||||
spin_lock_init(&phys_enc->spin_lock);
|
||||
|
||||
DBG("Created sde_encoder_phys_vid for intf %d", phys_enc->hw_intf->idx);
|
||||
|
||||
return phys_enc;
|
||||
|
||||
fail:
|
||||
DRM_ERROR("Failed to create encoder\n");
|
||||
if (vid_enc)
|
||||
sde_encoder_phys_vid_destroy(phys_enc);
|
||||
|
||||
return ERR_PTR(ret);
|
||||
}
|
Loading…
Add table
Reference in a new issue