Merge branch 'msm-next' of git://people.freedesktop.org/~robclark/linux into drm-next
1) support for "stolen mem" for splash-screen take-over 2) additional hdmi pixel clks 3) various pipe flush related fixes 4) support for snapdragon 410 (8x16) 5) support for DSI and dual-DSI It includes one small patch to export tile-group functions (which was ack'd by you), as these are used to explain to userspace dual-dsi configurations (with left and right tile). * 'msm-next' of git://people.freedesktop.org/~robclark/linux: (24 commits) drm/msm/mdp5: Enable DSI connector in msm drm driver drm/msm: Initial add DSI connector support drm/msm: Add split display interface drm/msm/mdp5: Move *_modeset_init out of construct_encoder function drm: export tile-group functions drm/msm/mdp5: Remove CTL flush dummy bits drm/msm/mdp5: Update headers (add CTL flush bits) drm/msm/mdp5: Add hardware configuration for msm8x16 drm/msm/mdp5: Get SMP client list from mdp5_cfg drm/msm/mdp5: Update headers (remove enum mdp5_client_id) drm/msm/mdp5: Separate MDP5 domain from MDSS domain drm/msm/mdp5: Update headers (introduce MDP5 domain) drm/msm/dsi: Update generated DSI header file drm/msm/mdp5: Fix PIPE source image size settings drm/msm/mdp5: Update generated mdp5 header file with DSI support drm/msm/mdp5: Add pingpong entry to mdp5 config table drm/msm/mdp5: Make the intf connection in config module drm/msm/mdp5: Add START signal to kick off certain pipelines drm/msm/mdp5: Enhance operation mode for pipeline configuration drm/msm/mdp5: Update generated header files ...
This commit is contained in:
commit
fa37a8c823
|
@ -5599,6 +5599,7 @@ struct drm_tile_group *drm_mode_get_tile_group(struct drm_device *dev,
|
|||
mutex_unlock(&dev->mode_config.idr_mutex);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_mode_get_tile_group);
|
||||
|
||||
/**
|
||||
* drm_mode_create_tile_group - create a tile group from a displayid description
|
||||
|
@ -5637,3 +5638,4 @@ struct drm_tile_group *drm_mode_create_tile_group(struct drm_device *dev,
|
|||
mutex_unlock(&dev->mode_config.idr_mutex);
|
||||
return tg;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_mode_create_tile_group);
|
||||
|
|
|
@ -35,3 +35,14 @@ config DRM_MSM_REGISTER_LOGGING
|
|||
Compile in support for logging register reads/writes in a format
|
||||
that can be parsed by envytools demsm tool. If enabled, register
|
||||
logging can be switched on via msm.reglog=y module param.
|
||||
|
||||
config DRM_MSM_DSI
|
||||
bool "Enable DSI support in MSM DRM driver"
|
||||
depends on DRM_MSM
|
||||
select DRM_PANEL
|
||||
select DRM_MIPI_DSI
|
||||
default y
|
||||
help
|
||||
Choose this option if you have a need for MIPI DSI connector
|
||||
support.
|
||||
|
||||
|
|
|
@ -50,5 +50,10 @@ msm-y := \
|
|||
|
||||
msm-$(CONFIG_DRM_MSM_FBDEV) += msm_fbdev.o
|
||||
msm-$(CONFIG_COMMON_CLK) += mdp/mdp4/mdp4_lvds_pll.o
|
||||
msm-$(CONFIG_DRM_MSM_DSI) += dsi/dsi.o \
|
||||
dsi/dsi_host.o \
|
||||
dsi/dsi_manager.o \
|
||||
dsi/dsi_phy.o \
|
||||
mdp/mdp5/mdp5_cmd_encoder.o
|
||||
|
||||
obj-$(CONFIG_DRM_MSM) += msm.o
|
||||
|
|
|
@ -0,0 +1,212 @@
|
|||
/*
|
||||
* 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 "dsi.h"
|
||||
|
||||
struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi)
|
||||
{
|
||||
if (!msm_dsi || !msm_dsi->panel)
|
||||
return NULL;
|
||||
|
||||
return (msm_dsi->panel_flags & MIPI_DSI_MODE_VIDEO) ?
|
||||
msm_dsi->encoders[MSM_DSI_VIDEO_ENCODER_ID] :
|
||||
msm_dsi->encoders[MSM_DSI_CMD_ENCODER_ID];
|
||||
}
|
||||
|
||||
static void dsi_destroy(struct msm_dsi *msm_dsi)
|
||||
{
|
||||
if (!msm_dsi)
|
||||
return;
|
||||
|
||||
msm_dsi_manager_unregister(msm_dsi);
|
||||
if (msm_dsi->host) {
|
||||
msm_dsi_host_destroy(msm_dsi->host);
|
||||
msm_dsi->host = NULL;
|
||||
}
|
||||
|
||||
platform_set_drvdata(msm_dsi->pdev, NULL);
|
||||
}
|
||||
|
||||
static struct msm_dsi *dsi_init(struct platform_device *pdev)
|
||||
{
|
||||
struct msm_dsi *msm_dsi = NULL;
|
||||
int ret;
|
||||
|
||||
if (!pdev) {
|
||||
dev_err(&pdev->dev, "no dsi device\n");
|
||||
ret = -ENXIO;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
msm_dsi = devm_kzalloc(&pdev->dev, sizeof(*msm_dsi), GFP_KERNEL);
|
||||
if (!msm_dsi) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
DBG("dsi probed=%p", msm_dsi);
|
||||
|
||||
msm_dsi->pdev = pdev;
|
||||
platform_set_drvdata(pdev, msm_dsi);
|
||||
|
||||
/* Init dsi host */
|
||||
ret = msm_dsi_host_init(msm_dsi);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
/* Register to dsi manager */
|
||||
ret = msm_dsi_manager_register(msm_dsi);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
return msm_dsi;
|
||||
|
||||
fail:
|
||||
if (msm_dsi)
|
||||
dsi_destroy(msm_dsi);
|
||||
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
static int dsi_bind(struct device *dev, struct device *master, void *data)
|
||||
{
|
||||
struct drm_device *drm = dev_get_drvdata(master);
|
||||
struct msm_drm_private *priv = drm->dev_private;
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct msm_dsi *msm_dsi;
|
||||
|
||||
DBG("");
|
||||
msm_dsi = dsi_init(pdev);
|
||||
if (IS_ERR(msm_dsi))
|
||||
return PTR_ERR(msm_dsi);
|
||||
|
||||
priv->dsi[msm_dsi->id] = msm_dsi;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dsi_unbind(struct device *dev, struct device *master,
|
||||
void *data)
|
||||
{
|
||||
struct drm_device *drm = dev_get_drvdata(master);
|
||||
struct msm_drm_private *priv = drm->dev_private;
|
||||
struct msm_dsi *msm_dsi = dev_get_drvdata(dev);
|
||||
int id = msm_dsi->id;
|
||||
|
||||
if (priv->dsi[id]) {
|
||||
dsi_destroy(msm_dsi);
|
||||
priv->dsi[id] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct component_ops dsi_ops = {
|
||||
.bind = dsi_bind,
|
||||
.unbind = dsi_unbind,
|
||||
};
|
||||
|
||||
static int dsi_dev_probe(struct platform_device *pdev)
|
||||
{
|
||||
return component_add(&pdev->dev, &dsi_ops);
|
||||
}
|
||||
|
||||
static int dsi_dev_remove(struct platform_device *pdev)
|
||||
{
|
||||
DBG("");
|
||||
component_del(&pdev->dev, &dsi_ops);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id dt_match[] = {
|
||||
{ .compatible = "qcom,mdss-dsi-ctrl" },
|
||||
{}
|
||||
};
|
||||
|
||||
static struct platform_driver dsi_driver = {
|
||||
.probe = dsi_dev_probe,
|
||||
.remove = dsi_dev_remove,
|
||||
.driver = {
|
||||
.name = "msm_dsi",
|
||||
.of_match_table = dt_match,
|
||||
},
|
||||
};
|
||||
|
||||
void __init msm_dsi_register(void)
|
||||
{
|
||||
DBG("");
|
||||
platform_driver_register(&dsi_driver);
|
||||
}
|
||||
|
||||
void __exit msm_dsi_unregister(void)
|
||||
{
|
||||
DBG("");
|
||||
platform_driver_unregister(&dsi_driver);
|
||||
}
|
||||
|
||||
int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
|
||||
struct drm_encoder *encoders[MSM_DSI_ENCODER_NUM])
|
||||
{
|
||||
struct msm_drm_private *priv = dev->dev_private;
|
||||
int ret, i;
|
||||
|
||||
if (WARN_ON(!encoders[MSM_DSI_VIDEO_ENCODER_ID] ||
|
||||
!encoders[MSM_DSI_CMD_ENCODER_ID]))
|
||||
return -EINVAL;
|
||||
|
||||
msm_dsi->dev = dev;
|
||||
|
||||
ret = msm_dsi_host_modeset_init(msm_dsi->host, dev);
|
||||
if (ret) {
|
||||
dev_err(dev->dev, "failed to modeset init host: %d\n", ret);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
msm_dsi->bridge = msm_dsi_manager_bridge_init(msm_dsi->id);
|
||||
if (IS_ERR(msm_dsi->bridge)) {
|
||||
ret = PTR_ERR(msm_dsi->bridge);
|
||||
dev_err(dev->dev, "failed to create dsi bridge: %d\n", ret);
|
||||
msm_dsi->bridge = NULL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
msm_dsi->connector = msm_dsi_manager_connector_init(msm_dsi->id);
|
||||
if (IS_ERR(msm_dsi->connector)) {
|
||||
ret = PTR_ERR(msm_dsi->connector);
|
||||
dev_err(dev->dev, "failed to create dsi connector: %d\n", ret);
|
||||
msm_dsi->connector = NULL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
for (i = 0; i < MSM_DSI_ENCODER_NUM; i++) {
|
||||
encoders[i]->bridge = msm_dsi->bridge;
|
||||
msm_dsi->encoders[i] = encoders[i];
|
||||
}
|
||||
|
||||
priv->bridges[priv->num_bridges++] = msm_dsi->bridge;
|
||||
priv->connectors[priv->num_connectors++] = msm_dsi->connector;
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
if (msm_dsi) {
|
||||
/* bridge/connector are normally destroyed by drm: */
|
||||
if (msm_dsi->bridge) {
|
||||
msm_dsi_manager_bridge_destroy(msm_dsi->bridge);
|
||||
msm_dsi->bridge = NULL;
|
||||
}
|
||||
if (msm_dsi->connector) {
|
||||
msm_dsi->connector->funcs->destroy(msm_dsi->connector);
|
||||
msm_dsi->connector = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* 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 __DSI_CONNECTOR_H__
|
||||
#define __DSI_CONNECTOR_H__
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "drm_crtc.h"
|
||||
#include "drm_mipi_dsi.h"
|
||||
#include "drm_panel.h"
|
||||
|
||||
#include "msm_drv.h"
|
||||
|
||||
#define DSI_0 0
|
||||
#define DSI_1 1
|
||||
#define DSI_MAX 2
|
||||
|
||||
#define DSI_CLOCK_MASTER DSI_0
|
||||
#define DSI_CLOCK_SLAVE DSI_1
|
||||
|
||||
#define DSI_LEFT DSI_0
|
||||
#define DSI_RIGHT DSI_1
|
||||
|
||||
/* According to the current drm framework sequence, take the encoder of
|
||||
* DSI_1 as master encoder
|
||||
*/
|
||||
#define DSI_ENCODER_MASTER DSI_1
|
||||
#define DSI_ENCODER_SLAVE DSI_0
|
||||
|
||||
struct msm_dsi {
|
||||
struct drm_device *dev;
|
||||
struct platform_device *pdev;
|
||||
|
||||
struct drm_connector *connector;
|
||||
struct drm_bridge *bridge;
|
||||
|
||||
struct mipi_dsi_host *host;
|
||||
struct msm_dsi_phy *phy;
|
||||
struct drm_panel *panel;
|
||||
unsigned long panel_flags;
|
||||
bool phy_enabled;
|
||||
|
||||
/* the encoders we are hooked to (outside of dsi block) */
|
||||
struct drm_encoder *encoders[MSM_DSI_ENCODER_NUM];
|
||||
|
||||
int id;
|
||||
};
|
||||
|
||||
/* dsi manager */
|
||||
struct drm_bridge *msm_dsi_manager_bridge_init(u8 id);
|
||||
void msm_dsi_manager_bridge_destroy(struct drm_bridge *bridge);
|
||||
struct drm_connector *msm_dsi_manager_connector_init(u8 id);
|
||||
int msm_dsi_manager_phy_enable(int id,
|
||||
const unsigned long bit_rate, const unsigned long esc_rate,
|
||||
u32 *clk_pre, u32 *clk_post);
|
||||
void msm_dsi_manager_phy_disable(int id);
|
||||
int msm_dsi_manager_cmd_xfer(int id, const struct mipi_dsi_msg *msg);
|
||||
bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 iova, u32 len);
|
||||
int msm_dsi_manager_register(struct msm_dsi *msm_dsi);
|
||||
void msm_dsi_manager_unregister(struct msm_dsi *msm_dsi);
|
||||
|
||||
/* msm dsi */
|
||||
struct drm_encoder *msm_dsi_get_encoder(struct msm_dsi *msm_dsi);
|
||||
|
||||
/* dsi host */
|
||||
int msm_dsi_host_xfer_prepare(struct mipi_dsi_host *host,
|
||||
const struct mipi_dsi_msg *msg);
|
||||
void msm_dsi_host_xfer_restore(struct mipi_dsi_host *host,
|
||||
const struct mipi_dsi_msg *msg);
|
||||
int msm_dsi_host_cmd_tx(struct mipi_dsi_host *host,
|
||||
const struct mipi_dsi_msg *msg);
|
||||
int msm_dsi_host_cmd_rx(struct mipi_dsi_host *host,
|
||||
const struct mipi_dsi_msg *msg);
|
||||
void msm_dsi_host_cmd_xfer_commit(struct mipi_dsi_host *host,
|
||||
u32 iova, u32 len);
|
||||
int msm_dsi_host_enable(struct mipi_dsi_host *host);
|
||||
int msm_dsi_host_disable(struct mipi_dsi_host *host);
|
||||
int msm_dsi_host_power_on(struct mipi_dsi_host *host);
|
||||
int msm_dsi_host_power_off(struct mipi_dsi_host *host);
|
||||
int msm_dsi_host_set_display_mode(struct mipi_dsi_host *host,
|
||||
struct drm_display_mode *mode);
|
||||
struct drm_panel *msm_dsi_host_get_panel(struct mipi_dsi_host *host,
|
||||
unsigned long *panel_flags);
|
||||
int msm_dsi_host_register(struct mipi_dsi_host *host, bool check_defer);
|
||||
void msm_dsi_host_unregister(struct mipi_dsi_host *host);
|
||||
void msm_dsi_host_destroy(struct mipi_dsi_host *host);
|
||||
int msm_dsi_host_modeset_init(struct mipi_dsi_host *host,
|
||||
struct drm_device *dev);
|
||||
int msm_dsi_host_init(struct msm_dsi *msm_dsi);
|
||||
|
||||
/* dsi phy */
|
||||
struct msm_dsi_phy;
|
||||
enum msm_dsi_phy_type {
|
||||
MSM_DSI_PHY_UNKNOWN,
|
||||
MSM_DSI_PHY_28NM,
|
||||
MSM_DSI_PHY_MAX
|
||||
};
|
||||
struct msm_dsi_phy *msm_dsi_phy_init(struct platform_device *pdev,
|
||||
enum msm_dsi_phy_type type, int id);
|
||||
int msm_dsi_phy_enable(struct msm_dsi_phy *phy, bool is_dual_panel,
|
||||
const unsigned long bit_rate, const unsigned long esc_rate);
|
||||
int msm_dsi_phy_disable(struct msm_dsi_phy *phy);
|
||||
void msm_dsi_phy_get_clk_pre_post(struct msm_dsi_phy *phy,
|
||||
u32 *clk_pre, u32 *clk_post);
|
||||
#endif /* __DSI_CONNECTOR_H__ */
|
||||
|
|
@ -8,19 +8,10 @@ http://github.com/freedreno/envytools/
|
|||
git clone https://github.com/freedreno/envytools.git
|
||||
|
||||
The rules-ng-ng source files this header was generated from are:
|
||||
- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2014-12-05 15:34:49)
|
||||
- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27)
|
||||
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20908 bytes, from 2014-12-08 16:13:00)
|
||||
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2357 bytes, from 2014-12-08 16:13:00)
|
||||
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 27208 bytes, from 2015-01-13 23:56:11)
|
||||
- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 11712 bytes, from 2013-08-17 17:13:43)
|
||||
- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2013-08-11 19:26:32)
|
||||
- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2014-10-31 16:48:57)
|
||||
- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2013-07-05 19:21:12)
|
||||
- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 26848 bytes, from 2015-01-13 23:55:57)
|
||||
- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 8253 bytes, from 2014-12-08 16:13:00)
|
||||
- /usr2/hali/local/envytools/envytools/rnndb/dsi/dsi.xml ( 18681 bytes, from 2015-03-04 23:08:31)
|
||||
- /usr2/hali/local/envytools/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2015-01-28 21:43:22)
|
||||
|
||||
Copyright (C) 2013 by the following authors:
|
||||
Copyright (C) 2013-2015 by the following authors:
|
||||
- Rob Clark <robdclark@gmail.com> (robclark)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
|
@ -51,11 +42,11 @@ enum dsi_traffic_mode {
|
|||
BURST_MODE = 2,
|
||||
};
|
||||
|
||||
enum dsi_dst_format {
|
||||
DST_FORMAT_RGB565 = 0,
|
||||
DST_FORMAT_RGB666 = 1,
|
||||
DST_FORMAT_RGB666_LOOSE = 2,
|
||||
DST_FORMAT_RGB888 = 3,
|
||||
enum dsi_vid_dst_format {
|
||||
VID_DST_FORMAT_RGB565 = 0,
|
||||
VID_DST_FORMAT_RGB666 = 1,
|
||||
VID_DST_FORMAT_RGB666_LOOSE = 2,
|
||||
VID_DST_FORMAT_RGB888 = 3,
|
||||
};
|
||||
|
||||
enum dsi_rgb_swap {
|
||||
|
@ -69,20 +60,63 @@ enum dsi_rgb_swap {
|
|||
|
||||
enum dsi_cmd_trigger {
|
||||
TRIGGER_NONE = 0,
|
||||
TRIGGER_SEOF = 1,
|
||||
TRIGGER_TE = 2,
|
||||
TRIGGER_SW = 4,
|
||||
TRIGGER_SW_SEOF = 5,
|
||||
TRIGGER_SW_TE = 6,
|
||||
};
|
||||
|
||||
enum dsi_cmd_dst_format {
|
||||
CMD_DST_FORMAT_RGB111 = 0,
|
||||
CMD_DST_FORMAT_RGB332 = 3,
|
||||
CMD_DST_FORMAT_RGB444 = 4,
|
||||
CMD_DST_FORMAT_RGB565 = 6,
|
||||
CMD_DST_FORMAT_RGB666 = 7,
|
||||
CMD_DST_FORMAT_RGB888 = 8,
|
||||
};
|
||||
|
||||
enum dsi_lane_swap {
|
||||
LANE_SWAP_0123 = 0,
|
||||
LANE_SWAP_3012 = 1,
|
||||
LANE_SWAP_2301 = 2,
|
||||
LANE_SWAP_1230 = 3,
|
||||
LANE_SWAP_0321 = 4,
|
||||
LANE_SWAP_1032 = 5,
|
||||
LANE_SWAP_2103 = 6,
|
||||
LANE_SWAP_3210 = 7,
|
||||
};
|
||||
|
||||
#define DSI_IRQ_CMD_DMA_DONE 0x00000001
|
||||
#define DSI_IRQ_MASK_CMD_DMA_DONE 0x00000002
|
||||
#define DSI_IRQ_CMD_MDP_DONE 0x00000100
|
||||
#define DSI_IRQ_MASK_CMD_MDP_DONE 0x00000200
|
||||
#define DSI_IRQ_VIDEO_DONE 0x00010000
|
||||
#define DSI_IRQ_MASK_VIDEO_DONE 0x00020000
|
||||
#define DSI_IRQ_BTA_DONE 0x00100000
|
||||
#define DSI_IRQ_MASK_BTA_DONE 0x00200000
|
||||
#define DSI_IRQ_ERROR 0x01000000
|
||||
#define DSI_IRQ_MASK_ERROR 0x02000000
|
||||
#define REG_DSI_6G_HW_VERSION 0x00000000
|
||||
#define DSI_6G_HW_VERSION_MAJOR__MASK 0xf0000000
|
||||
#define DSI_6G_HW_VERSION_MAJOR__SHIFT 28
|
||||
static inline uint32_t DSI_6G_HW_VERSION_MAJOR(uint32_t val)
|
||||
{
|
||||
return ((val) << DSI_6G_HW_VERSION_MAJOR__SHIFT) & DSI_6G_HW_VERSION_MAJOR__MASK;
|
||||
}
|
||||
#define DSI_6G_HW_VERSION_MINOR__MASK 0x0fff0000
|
||||
#define DSI_6G_HW_VERSION_MINOR__SHIFT 16
|
||||
static inline uint32_t DSI_6G_HW_VERSION_MINOR(uint32_t val)
|
||||
{
|
||||
return ((val) << DSI_6G_HW_VERSION_MINOR__SHIFT) & DSI_6G_HW_VERSION_MINOR__MASK;
|
||||
}
|
||||
#define DSI_6G_HW_VERSION_STEP__MASK 0x0000ffff
|
||||
#define DSI_6G_HW_VERSION_STEP__SHIFT 0
|
||||
static inline uint32_t DSI_6G_HW_VERSION_STEP(uint32_t val)
|
||||
{
|
||||
return ((val) << DSI_6G_HW_VERSION_STEP__SHIFT) & DSI_6G_HW_VERSION_STEP__MASK;
|
||||
}
|
||||
|
||||
#define REG_DSI_CTRL 0x00000000
|
||||
#define DSI_CTRL_ENABLE 0x00000001
|
||||
#define DSI_CTRL_VID_MODE_EN 0x00000002
|
||||
|
@ -96,11 +130,15 @@ enum dsi_cmd_trigger {
|
|||
#define DSI_CTRL_CRC_CHECK 0x01000000
|
||||
|
||||
#define REG_DSI_STATUS0 0x00000004
|
||||
#define DSI_STATUS0_CMD_MODE_ENGINE_BUSY 0x00000001
|
||||
#define DSI_STATUS0_CMD_MODE_DMA_BUSY 0x00000002
|
||||
#define DSI_STATUS0_CMD_MODE_MDP_BUSY 0x00000004
|
||||
#define DSI_STATUS0_VIDEO_MODE_ENGINE_BUSY 0x00000008
|
||||
#define DSI_STATUS0_DSI_BUSY 0x00000010
|
||||
#define DSI_STATUS0_INTERLEAVE_OP_CONTENTION 0x80000000
|
||||
|
||||
#define REG_DSI_FIFO_STATUS 0x00000008
|
||||
#define DSI_FIFO_STATUS_CMD_MDP_FIFO_UNDERFLOW 0x00000080
|
||||
|
||||
#define REG_DSI_VID_CFG0 0x0000000c
|
||||
#define DSI_VID_CFG0_VIRT_CHANNEL__MASK 0x00000003
|
||||
|
@ -111,7 +149,7 @@ static inline uint32_t DSI_VID_CFG0_VIRT_CHANNEL(uint32_t val)
|
|||
}
|
||||
#define DSI_VID_CFG0_DST_FORMAT__MASK 0x00000030
|
||||
#define DSI_VID_CFG0_DST_FORMAT__SHIFT 4
|
||||
static inline uint32_t DSI_VID_CFG0_DST_FORMAT(enum dsi_dst_format val)
|
||||
static inline uint32_t DSI_VID_CFG0_DST_FORMAT(enum dsi_vid_dst_format val)
|
||||
{
|
||||
return ((val) << DSI_VID_CFG0_DST_FORMAT__SHIFT) & DSI_VID_CFG0_DST_FORMAT__MASK;
|
||||
}
|
||||
|
@ -129,21 +167,15 @@ static inline uint32_t DSI_VID_CFG0_TRAFFIC_MODE(enum dsi_traffic_mode val)
|
|||
#define DSI_VID_CFG0_PULSE_MODE_HSA_HE 0x10000000
|
||||
|
||||
#define REG_DSI_VID_CFG1 0x0000001c
|
||||
#define DSI_VID_CFG1_R_SEL 0x00000010
|
||||
#define DSI_VID_CFG1_G_SEL 0x00000100
|
||||
#define DSI_VID_CFG1_B_SEL 0x00001000
|
||||
#define DSI_VID_CFG1_RGB_SWAP__MASK 0x00070000
|
||||
#define DSI_VID_CFG1_RGB_SWAP__SHIFT 16
|
||||
#define DSI_VID_CFG1_R_SEL 0x00000001
|
||||
#define DSI_VID_CFG1_G_SEL 0x00000010
|
||||
#define DSI_VID_CFG1_B_SEL 0x00000100
|
||||
#define DSI_VID_CFG1_RGB_SWAP__MASK 0x00007000
|
||||
#define DSI_VID_CFG1_RGB_SWAP__SHIFT 12
|
||||
static inline uint32_t DSI_VID_CFG1_RGB_SWAP(enum dsi_rgb_swap val)
|
||||
{
|
||||
return ((val) << DSI_VID_CFG1_RGB_SWAP__SHIFT) & DSI_VID_CFG1_RGB_SWAP__MASK;
|
||||
}
|
||||
#define DSI_VID_CFG1_INTERLEAVE_MAX__MASK 0x00f00000
|
||||
#define DSI_VID_CFG1_INTERLEAVE_MAX__SHIFT 20
|
||||
static inline uint32_t DSI_VID_CFG1_INTERLEAVE_MAX(uint32_t val)
|
||||
{
|
||||
return ((val) << DSI_VID_CFG1_INTERLEAVE_MAX__SHIFT) & DSI_VID_CFG1_INTERLEAVE_MAX__MASK;
|
||||
}
|
||||
|
||||
#define REG_DSI_ACTIVE_H 0x00000020
|
||||
#define DSI_ACTIVE_H_START__MASK 0x00000fff
|
||||
|
@ -201,32 +233,115 @@ static inline uint32_t DSI_ACTIVE_HSYNC_END(uint32_t val)
|
|||
return ((val) << DSI_ACTIVE_HSYNC_END__SHIFT) & DSI_ACTIVE_HSYNC_END__MASK;
|
||||
}
|
||||
|
||||
#define REG_DSI_ACTIVE_VSYNC 0x00000034
|
||||
#define DSI_ACTIVE_VSYNC_START__MASK 0x00000fff
|
||||
#define DSI_ACTIVE_VSYNC_START__SHIFT 0
|
||||
static inline uint32_t DSI_ACTIVE_VSYNC_START(uint32_t val)
|
||||
#define REG_DSI_ACTIVE_VSYNC_HPOS 0x00000030
|
||||
#define DSI_ACTIVE_VSYNC_HPOS_START__MASK 0x00000fff
|
||||
#define DSI_ACTIVE_VSYNC_HPOS_START__SHIFT 0
|
||||
static inline uint32_t DSI_ACTIVE_VSYNC_HPOS_START(uint32_t val)
|
||||
{
|
||||
return ((val) << DSI_ACTIVE_VSYNC_START__SHIFT) & DSI_ACTIVE_VSYNC_START__MASK;
|
||||
return ((val) << DSI_ACTIVE_VSYNC_HPOS_START__SHIFT) & DSI_ACTIVE_VSYNC_HPOS_START__MASK;
|
||||
}
|
||||
#define DSI_ACTIVE_VSYNC_END__MASK 0x0fff0000
|
||||
#define DSI_ACTIVE_VSYNC_END__SHIFT 16
|
||||
static inline uint32_t DSI_ACTIVE_VSYNC_END(uint32_t val)
|
||||
#define DSI_ACTIVE_VSYNC_HPOS_END__MASK 0x0fff0000
|
||||
#define DSI_ACTIVE_VSYNC_HPOS_END__SHIFT 16
|
||||
static inline uint32_t DSI_ACTIVE_VSYNC_HPOS_END(uint32_t val)
|
||||
{
|
||||
return ((val) << DSI_ACTIVE_VSYNC_END__SHIFT) & DSI_ACTIVE_VSYNC_END__MASK;
|
||||
return ((val) << DSI_ACTIVE_VSYNC_HPOS_END__SHIFT) & DSI_ACTIVE_VSYNC_HPOS_END__MASK;
|
||||
}
|
||||
|
||||
#define REG_DSI_ACTIVE_VSYNC_VPOS 0x00000034
|
||||
#define DSI_ACTIVE_VSYNC_VPOS_START__MASK 0x00000fff
|
||||
#define DSI_ACTIVE_VSYNC_VPOS_START__SHIFT 0
|
||||
static inline uint32_t DSI_ACTIVE_VSYNC_VPOS_START(uint32_t val)
|
||||
{
|
||||
return ((val) << DSI_ACTIVE_VSYNC_VPOS_START__SHIFT) & DSI_ACTIVE_VSYNC_VPOS_START__MASK;
|
||||
}
|
||||
#define DSI_ACTIVE_VSYNC_VPOS_END__MASK 0x0fff0000
|
||||
#define DSI_ACTIVE_VSYNC_VPOS_END__SHIFT 16
|
||||
static inline uint32_t DSI_ACTIVE_VSYNC_VPOS_END(uint32_t val)
|
||||
{
|
||||
return ((val) << DSI_ACTIVE_VSYNC_VPOS_END__SHIFT) & DSI_ACTIVE_VSYNC_VPOS_END__MASK;
|
||||
}
|
||||
|
||||
#define REG_DSI_CMD_DMA_CTRL 0x00000038
|
||||
#define DSI_CMD_DMA_CTRL_BROADCAST_EN 0x80000000
|
||||
#define DSI_CMD_DMA_CTRL_FROM_FRAME_BUFFER 0x10000000
|
||||
#define DSI_CMD_DMA_CTRL_LOW_POWER 0x04000000
|
||||
|
||||
#define REG_DSI_CMD_CFG0 0x0000003c
|
||||
#define DSI_CMD_CFG0_DST_FORMAT__MASK 0x0000000f
|
||||
#define DSI_CMD_CFG0_DST_FORMAT__SHIFT 0
|
||||
static inline uint32_t DSI_CMD_CFG0_DST_FORMAT(enum dsi_cmd_dst_format val)
|
||||
{
|
||||
return ((val) << DSI_CMD_CFG0_DST_FORMAT__SHIFT) & DSI_CMD_CFG0_DST_FORMAT__MASK;
|
||||
}
|
||||
#define DSI_CMD_CFG0_R_SEL 0x00000010
|
||||
#define DSI_CMD_CFG0_G_SEL 0x00000100
|
||||
#define DSI_CMD_CFG0_B_SEL 0x00001000
|
||||
#define DSI_CMD_CFG0_INTERLEAVE_MAX__MASK 0x00f00000
|
||||
#define DSI_CMD_CFG0_INTERLEAVE_MAX__SHIFT 20
|
||||
static inline uint32_t DSI_CMD_CFG0_INTERLEAVE_MAX(uint32_t val)
|
||||
{
|
||||
return ((val) << DSI_CMD_CFG0_INTERLEAVE_MAX__SHIFT) & DSI_CMD_CFG0_INTERLEAVE_MAX__MASK;
|
||||
}
|
||||
#define DSI_CMD_CFG0_RGB_SWAP__MASK 0x00070000
|
||||
#define DSI_CMD_CFG0_RGB_SWAP__SHIFT 16
|
||||
static inline uint32_t DSI_CMD_CFG0_RGB_SWAP(enum dsi_rgb_swap val)
|
||||
{
|
||||
return ((val) << DSI_CMD_CFG0_RGB_SWAP__SHIFT) & DSI_CMD_CFG0_RGB_SWAP__MASK;
|
||||
}
|
||||
|
||||
#define REG_DSI_CMD_CFG1 0x00000040
|
||||
#define DSI_CMD_CFG1_WR_MEM_START__MASK 0x000000ff
|
||||
#define DSI_CMD_CFG1_WR_MEM_START__SHIFT 0
|
||||
static inline uint32_t DSI_CMD_CFG1_WR_MEM_START(uint32_t val)
|
||||
{
|
||||
return ((val) << DSI_CMD_CFG1_WR_MEM_START__SHIFT) & DSI_CMD_CFG1_WR_MEM_START__MASK;
|
||||
}
|
||||
#define DSI_CMD_CFG1_WR_MEM_CONTINUE__MASK 0x0000ff00
|
||||
#define DSI_CMD_CFG1_WR_MEM_CONTINUE__SHIFT 8
|
||||
static inline uint32_t DSI_CMD_CFG1_WR_MEM_CONTINUE(uint32_t val)
|
||||
{
|
||||
return ((val) << DSI_CMD_CFG1_WR_MEM_CONTINUE__SHIFT) & DSI_CMD_CFG1_WR_MEM_CONTINUE__MASK;
|
||||
}
|
||||
#define DSI_CMD_CFG1_INSERT_DCS_COMMAND 0x00010000
|
||||
|
||||
#define REG_DSI_DMA_BASE 0x00000044
|
||||
|
||||
#define REG_DSI_DMA_LEN 0x00000048
|
||||
|
||||
#define REG_DSI_CMD_MDP_STREAM_CTRL 0x00000054
|
||||
#define DSI_CMD_MDP_STREAM_CTRL_DATA_TYPE__MASK 0x0000003f
|
||||
#define DSI_CMD_MDP_STREAM_CTRL_DATA_TYPE__SHIFT 0
|
||||
static inline uint32_t DSI_CMD_MDP_STREAM_CTRL_DATA_TYPE(uint32_t val)
|
||||
{
|
||||
return ((val) << DSI_CMD_MDP_STREAM_CTRL_DATA_TYPE__SHIFT) & DSI_CMD_MDP_STREAM_CTRL_DATA_TYPE__MASK;
|
||||
}
|
||||
#define DSI_CMD_MDP_STREAM_CTRL_VIRTUAL_CHANNEL__MASK 0x00000300
|
||||
#define DSI_CMD_MDP_STREAM_CTRL_VIRTUAL_CHANNEL__SHIFT 8
|
||||
static inline uint32_t DSI_CMD_MDP_STREAM_CTRL_VIRTUAL_CHANNEL(uint32_t val)
|
||||
{
|
||||
return ((val) << DSI_CMD_MDP_STREAM_CTRL_VIRTUAL_CHANNEL__SHIFT) & DSI_CMD_MDP_STREAM_CTRL_VIRTUAL_CHANNEL__MASK;
|
||||
}
|
||||
#define DSI_CMD_MDP_STREAM_CTRL_WORD_COUNT__MASK 0xffff0000
|
||||
#define DSI_CMD_MDP_STREAM_CTRL_WORD_COUNT__SHIFT 16
|
||||
static inline uint32_t DSI_CMD_MDP_STREAM_CTRL_WORD_COUNT(uint32_t val)
|
||||
{
|
||||
return ((val) << DSI_CMD_MDP_STREAM_CTRL_WORD_COUNT__SHIFT) & DSI_CMD_MDP_STREAM_CTRL_WORD_COUNT__MASK;
|
||||
}
|
||||
|
||||
#define REG_DSI_CMD_MDP_STREAM_TOTAL 0x00000058
|
||||
#define DSI_CMD_MDP_STREAM_TOTAL_H_TOTAL__MASK 0x00000fff
|
||||
#define DSI_CMD_MDP_STREAM_TOTAL_H_TOTAL__SHIFT 0
|
||||
static inline uint32_t DSI_CMD_MDP_STREAM_TOTAL_H_TOTAL(uint32_t val)
|
||||
{
|
||||
return ((val) << DSI_CMD_MDP_STREAM_TOTAL_H_TOTAL__SHIFT) & DSI_CMD_MDP_STREAM_TOTAL_H_TOTAL__MASK;
|
||||
}
|
||||
#define DSI_CMD_MDP_STREAM_TOTAL_V_TOTAL__MASK 0x0fff0000
|
||||
#define DSI_CMD_MDP_STREAM_TOTAL_V_TOTAL__SHIFT 16
|
||||
static inline uint32_t DSI_CMD_MDP_STREAM_TOTAL_V_TOTAL(uint32_t val)
|
||||
{
|
||||
return ((val) << DSI_CMD_MDP_STREAM_TOTAL_V_TOTAL__SHIFT) & DSI_CMD_MDP_STREAM_TOTAL_V_TOTAL__MASK;
|
||||
}
|
||||
|
||||
#define REG_DSI_ACK_ERR_STATUS 0x00000064
|
||||
|
||||
static inline uint32_t REG_DSI_RDBK(uint32_t i0) { return 0x00000068 + 0x4*i0; }
|
||||
|
@ -234,19 +349,25 @@ static inline uint32_t REG_DSI_RDBK(uint32_t i0) { return 0x00000068 + 0x4*i0; }
|
|||
static inline uint32_t REG_DSI_RDBK_DATA(uint32_t i0) { return 0x00000068 + 0x4*i0; }
|
||||
|
||||
#define REG_DSI_TRIG_CTRL 0x00000080
|
||||
#define DSI_TRIG_CTRL_DMA_TRIGGER__MASK 0x0000000f
|
||||
#define DSI_TRIG_CTRL_DMA_TRIGGER__MASK 0x00000007
|
||||
#define DSI_TRIG_CTRL_DMA_TRIGGER__SHIFT 0
|
||||
static inline uint32_t DSI_TRIG_CTRL_DMA_TRIGGER(enum dsi_cmd_trigger val)
|
||||
{
|
||||
return ((val) << DSI_TRIG_CTRL_DMA_TRIGGER__SHIFT) & DSI_TRIG_CTRL_DMA_TRIGGER__MASK;
|
||||
}
|
||||
#define DSI_TRIG_CTRL_MDP_TRIGGER__MASK 0x000000f0
|
||||
#define DSI_TRIG_CTRL_MDP_TRIGGER__MASK 0x00000070
|
||||
#define DSI_TRIG_CTRL_MDP_TRIGGER__SHIFT 4
|
||||
static inline uint32_t DSI_TRIG_CTRL_MDP_TRIGGER(enum dsi_cmd_trigger val)
|
||||
{
|
||||
return ((val) << DSI_TRIG_CTRL_MDP_TRIGGER__SHIFT) & DSI_TRIG_CTRL_MDP_TRIGGER__MASK;
|
||||
}
|
||||
#define DSI_TRIG_CTRL_STREAM 0x00000100
|
||||
#define DSI_TRIG_CTRL_STREAM__MASK 0x00000300
|
||||
#define DSI_TRIG_CTRL_STREAM__SHIFT 8
|
||||
static inline uint32_t DSI_TRIG_CTRL_STREAM(uint32_t val)
|
||||
{
|
||||
return ((val) << DSI_TRIG_CTRL_STREAM__SHIFT) & DSI_TRIG_CTRL_STREAM__MASK;
|
||||
}
|
||||
#define DSI_TRIG_CTRL_BLOCK_DMA_WITHIN_FRAME 0x00001000
|
||||
#define DSI_TRIG_CTRL_TE 0x80000000
|
||||
|
||||
#define REG_DSI_TRIG_DMA 0x0000008c
|
||||
|
@ -274,6 +395,12 @@ static inline uint32_t DSI_CLKOUT_TIMING_CTRL_T_CLK_POST(uint32_t val)
|
|||
#define DSI_EOT_PACKET_CTRL_RX_EOT_IGNORE 0x00000010
|
||||
|
||||
#define REG_DSI_LANE_SWAP_CTRL 0x000000ac
|
||||
#define DSI_LANE_SWAP_CTRL_DLN_SWAP_SEL__MASK 0x00000007
|
||||
#define DSI_LANE_SWAP_CTRL_DLN_SWAP_SEL__SHIFT 0
|
||||
static inline uint32_t DSI_LANE_SWAP_CTRL_DLN_SWAP_SEL(enum dsi_lane_swap val)
|
||||
{
|
||||
return ((val) << DSI_LANE_SWAP_CTRL_DLN_SWAP_SEL__SHIFT) & DSI_LANE_SWAP_CTRL_DLN_SWAP_SEL__MASK;
|
||||
}
|
||||
|
||||
#define REG_DSI_ERR_INT_MASK0 0x00000108
|
||||
|
||||
|
@ -282,8 +409,36 @@ static inline uint32_t DSI_CLKOUT_TIMING_CTRL_T_CLK_POST(uint32_t val)
|
|||
#define REG_DSI_RESET 0x00000114
|
||||
|
||||
#define REG_DSI_CLK_CTRL 0x00000118
|
||||
#define DSI_CLK_CTRL_AHBS_HCLK_ON 0x00000001
|
||||
#define DSI_CLK_CTRL_AHBM_SCLK_ON 0x00000002
|
||||
#define DSI_CLK_CTRL_PCLK_ON 0x00000004
|
||||
#define DSI_CLK_CTRL_DSICLK_ON 0x00000008
|
||||
#define DSI_CLK_CTRL_BYTECLK_ON 0x00000010
|
||||
#define DSI_CLK_CTRL_ESCCLK_ON 0x00000020
|
||||
#define DSI_CLK_CTRL_FORCE_ON_DYN_AHBM_HCLK 0x00000200
|
||||
|
||||
#define REG_DSI_CLK_STATUS 0x0000011c
|
||||
#define DSI_CLK_STATUS_PLL_UNLOCKED 0x00010000
|
||||
|
||||
#define REG_DSI_PHY_RESET 0x00000128
|
||||
#define DSI_PHY_RESET_RESET 0x00000001
|
||||
|
||||
#define REG_DSI_RDBK_DATA_CTRL 0x000001d0
|
||||
#define DSI_RDBK_DATA_CTRL_COUNT__MASK 0x00ff0000
|
||||
#define DSI_RDBK_DATA_CTRL_COUNT__SHIFT 16
|
||||
static inline uint32_t DSI_RDBK_DATA_CTRL_COUNT(uint32_t val)
|
||||
{
|
||||
return ((val) << DSI_RDBK_DATA_CTRL_COUNT__SHIFT) & DSI_RDBK_DATA_CTRL_COUNT__MASK;
|
||||
}
|
||||
#define DSI_RDBK_DATA_CTRL_CLR 0x00000001
|
||||
|
||||
#define REG_DSI_VERSION 0x000001f0
|
||||
#define DSI_VERSION_MAJOR__MASK 0xff000000
|
||||
#define DSI_VERSION_MAJOR__SHIFT 24
|
||||
static inline uint32_t DSI_VERSION_MAJOR(uint32_t val)
|
||||
{
|
||||
return ((val) << DSI_VERSION_MAJOR__SHIFT) & DSI_VERSION_MAJOR__MASK;
|
||||
}
|
||||
|
||||
#define REG_DSI_PHY_PLL_CTRL_0 0x00000200
|
||||
#define DSI_PHY_PLL_CTRL_0_ENABLE 0x00000001
|
||||
|
@ -501,5 +656,184 @@ static inline uint32_t REG_DSI_8960_LN_TEST_STR_1(uint32_t i0) { return 0x000003
|
|||
#define REG_DSI_8960_PHY_CAL_STATUS 0x00000550
|
||||
#define DSI_8960_PHY_CAL_STATUS_CAL_BUSY 0x00000010
|
||||
|
||||
static inline uint32_t REG_DSI_28nm_PHY_LN(uint32_t i0) { return 0x00000000 + 0x40*i0; }
|
||||
|
||||
static inline uint32_t REG_DSI_28nm_PHY_LN_CFG_0(uint32_t i0) { return 0x00000000 + 0x40*i0; }
|
||||
|
||||
static inline uint32_t REG_DSI_28nm_PHY_LN_CFG_1(uint32_t i0) { return 0x00000004 + 0x40*i0; }
|
||||
|
||||
static inline uint32_t REG_DSI_28nm_PHY_LN_CFG_2(uint32_t i0) { return 0x00000008 + 0x40*i0; }
|
||||
|
||||
static inline uint32_t REG_DSI_28nm_PHY_LN_CFG_3(uint32_t i0) { return 0x0000000c + 0x40*i0; }
|
||||
|
||||
static inline uint32_t REG_DSI_28nm_PHY_LN_CFG_4(uint32_t i0) { return 0x00000010 + 0x40*i0; }
|
||||
|
||||
static inline uint32_t REG_DSI_28nm_PHY_LN_TEST_DATAPATH(uint32_t i0) { return 0x00000014 + 0x40*i0; }
|
||||
|
||||
static inline uint32_t REG_DSI_28nm_PHY_LN_DEBUG_SEL(uint32_t i0) { return 0x00000018 + 0x40*i0; }
|
||||
|
||||
static inline uint32_t REG_DSI_28nm_PHY_LN_TEST_STR_0(uint32_t i0) { return 0x0000001c + 0x40*i0; }
|
||||
|
||||
static inline uint32_t REG_DSI_28nm_PHY_LN_TEST_STR_1(uint32_t i0) { return 0x00000020 + 0x40*i0; }
|
||||
|
||||
#define REG_DSI_28nm_PHY_LNCK_CFG_0 0x00000100
|
||||
|
||||
#define REG_DSI_28nm_PHY_LNCK_CFG_1 0x00000104
|
||||
|
||||
#define REG_DSI_28nm_PHY_LNCK_CFG_2 0x00000108
|
||||
|
||||
#define REG_DSI_28nm_PHY_LNCK_CFG_3 0x0000010c
|
||||
|
||||
#define REG_DSI_28nm_PHY_LNCK_CFG_4 0x00000110
|
||||
|
||||
#define REG_DSI_28nm_PHY_LNCK_TEST_DATAPATH 0x00000114
|
||||
|
||||
#define REG_DSI_28nm_PHY_LNCK_DEBUG_SEL 0x00000118
|
||||
|
||||
#define REG_DSI_28nm_PHY_LNCK_TEST_STR0 0x0000011c
|
||||
|
||||
#define REG_DSI_28nm_PHY_LNCK_TEST_STR1 0x00000120
|
||||
|
||||
#define REG_DSI_28nm_PHY_TIMING_CTRL_0 0x00000140
|
||||
#define DSI_28nm_PHY_TIMING_CTRL_0_CLK_ZERO__MASK 0x000000ff
|
||||
#define DSI_28nm_PHY_TIMING_CTRL_0_CLK_ZERO__SHIFT 0
|
||||
static inline uint32_t DSI_28nm_PHY_TIMING_CTRL_0_CLK_ZERO(uint32_t val)
|
||||
{
|
||||
return ((val) << DSI_28nm_PHY_TIMING_CTRL_0_CLK_ZERO__SHIFT) & DSI_28nm_PHY_TIMING_CTRL_0_CLK_ZERO__MASK;
|
||||
}
|
||||
|
||||
#define REG_DSI_28nm_PHY_TIMING_CTRL_1 0x00000144
|
||||
#define DSI_28nm_PHY_TIMING_CTRL_1_CLK_TRAIL__MASK 0x000000ff
|
||||
#define DSI_28nm_PHY_TIMING_CTRL_1_CLK_TRAIL__SHIFT 0
|
||||
static inline uint32_t DSI_28nm_PHY_TIMING_CTRL_1_CLK_TRAIL(uint32_t val)
|
||||
{
|
||||
return ((val) << DSI_28nm_PHY_TIMING_CTRL_1_CLK_TRAIL__SHIFT) & DSI_28nm_PHY_TIMING_CTRL_1_CLK_TRAIL__MASK;
|
||||
}
|
||||
|
||||
#define REG_DSI_28nm_PHY_TIMING_CTRL_2 0x00000148
|
||||
#define DSI_28nm_PHY_TIMING_CTRL_2_CLK_PREPARE__MASK 0x000000ff
|
||||
#define DSI_28nm_PHY_TIMING_CTRL_2_CLK_PREPARE__SHIFT 0
|
||||
static inline uint32_t DSI_28nm_PHY_TIMING_CTRL_2_CLK_PREPARE(uint32_t val)
|
||||
{
|
||||
return ((val) << DSI_28nm_PHY_TIMING_CTRL_2_CLK_PREPARE__SHIFT) & DSI_28nm_PHY_TIMING_CTRL_2_CLK_PREPARE__MASK;
|
||||
}
|
||||
|
||||
#define REG_DSI_28nm_PHY_TIMING_CTRL_3 0x0000014c
|
||||
#define DSI_28nm_PHY_TIMING_CTRL_3_CLK_ZERO_8 0x00000001
|
||||
|
||||
#define REG_DSI_28nm_PHY_TIMING_CTRL_4 0x00000150
|
||||
#define DSI_28nm_PHY_TIMING_CTRL_4_HS_EXIT__MASK 0x000000ff
|
||||
#define DSI_28nm_PHY_TIMING_CTRL_4_HS_EXIT__SHIFT 0
|
||||
static inline uint32_t DSI_28nm_PHY_TIMING_CTRL_4_HS_EXIT(uint32_t val)
|
||||
{
|
||||
return ((val) << DSI_28nm_PHY_TIMING_CTRL_4_HS_EXIT__SHIFT) & DSI_28nm_PHY_TIMING_CTRL_4_HS_EXIT__MASK;
|
||||
}
|
||||
|
||||
#define REG_DSI_28nm_PHY_TIMING_CTRL_5 0x00000154
|
||||
#define DSI_28nm_PHY_TIMING_CTRL_5_HS_ZERO__MASK 0x000000ff
|
||||
#define DSI_28nm_PHY_TIMING_CTRL_5_HS_ZERO__SHIFT 0
|
||||
static inline uint32_t DSI_28nm_PHY_TIMING_CTRL_5_HS_ZERO(uint32_t val)
|
||||
{
|
||||
return ((val) << DSI_28nm_PHY_TIMING_CTRL_5_HS_ZERO__SHIFT) & DSI_28nm_PHY_TIMING_CTRL_5_HS_ZERO__MASK;
|
||||
}
|
||||
|
||||
#define REG_DSI_28nm_PHY_TIMING_CTRL_6 0x00000158
|
||||
#define DSI_28nm_PHY_TIMING_CTRL_6_HS_PREPARE__MASK 0x000000ff
|
||||
#define DSI_28nm_PHY_TIMING_CTRL_6_HS_PREPARE__SHIFT 0
|
||||
static inline uint32_t DSI_28nm_PHY_TIMING_CTRL_6_HS_PREPARE(uint32_t val)
|
||||
{
|
||||
return ((val) << DSI_28nm_PHY_TIMING_CTRL_6_HS_PREPARE__SHIFT) & DSI_28nm_PHY_TIMING_CTRL_6_HS_PREPARE__MASK;
|
||||
}
|
||||
|
||||
#define REG_DSI_28nm_PHY_TIMING_CTRL_7 0x0000015c
|
||||
#define DSI_28nm_PHY_TIMING_CTRL_7_HS_TRAIL__MASK 0x000000ff
|
||||
#define DSI_28nm_PHY_TIMING_CTRL_7_HS_TRAIL__SHIFT 0
|
||||
static inline uint32_t DSI_28nm_PHY_TIMING_CTRL_7_HS_TRAIL(uint32_t val)
|
||||
{
|
||||
return ((val) << DSI_28nm_PHY_TIMING_CTRL_7_HS_TRAIL__SHIFT) & DSI_28nm_PHY_TIMING_CTRL_7_HS_TRAIL__MASK;
|
||||
}
|
||||
|
||||
#define REG_DSI_28nm_PHY_TIMING_CTRL_8 0x00000160
|
||||
#define DSI_28nm_PHY_TIMING_CTRL_8_HS_RQST__MASK 0x000000ff
|
||||
#define DSI_28nm_PHY_TIMING_CTRL_8_HS_RQST__SHIFT 0
|
||||
static inline uint32_t DSI_28nm_PHY_TIMING_CTRL_8_HS_RQST(uint32_t val)
|
||||
{
|
||||
return ((val) << DSI_28nm_PHY_TIMING_CTRL_8_HS_RQST__SHIFT) & DSI_28nm_PHY_TIMING_CTRL_8_HS_RQST__MASK;
|
||||
}
|
||||
|
||||
#define REG_DSI_28nm_PHY_TIMING_CTRL_9 0x00000164
|
||||
#define DSI_28nm_PHY_TIMING_CTRL_9_TA_GO__MASK 0x00000007
|
||||
#define DSI_28nm_PHY_TIMING_CTRL_9_TA_GO__SHIFT 0
|
||||
static inline uint32_t DSI_28nm_PHY_TIMING_CTRL_9_TA_GO(uint32_t val)
|
||||
{
|
||||
return ((val) << DSI_28nm_PHY_TIMING_CTRL_9_TA_GO__SHIFT) & DSI_28nm_PHY_TIMING_CTRL_9_TA_GO__MASK;
|
||||
}
|
||||
#define DSI_28nm_PHY_TIMING_CTRL_9_TA_SURE__MASK 0x00000070
|
||||
#define DSI_28nm_PHY_TIMING_CTRL_9_TA_SURE__SHIFT 4
|
||||
static inline uint32_t DSI_28nm_PHY_TIMING_CTRL_9_TA_SURE(uint32_t val)
|
||||
{
|
||||
return ((val) << DSI_28nm_PHY_TIMING_CTRL_9_TA_SURE__SHIFT) & DSI_28nm_PHY_TIMING_CTRL_9_TA_SURE__MASK;
|
||||
}
|
||||
|
||||
#define REG_DSI_28nm_PHY_TIMING_CTRL_10 0x00000168
|
||||
#define DSI_28nm_PHY_TIMING_CTRL_10_TA_GET__MASK 0x00000007
|
||||
#define DSI_28nm_PHY_TIMING_CTRL_10_TA_GET__SHIFT 0
|
||||
static inline uint32_t DSI_28nm_PHY_TIMING_CTRL_10_TA_GET(uint32_t val)
|
||||
{
|
||||
return ((val) << DSI_28nm_PHY_TIMING_CTRL_10_TA_GET__SHIFT) & DSI_28nm_PHY_TIMING_CTRL_10_TA_GET__MASK;
|
||||
}
|
||||
|
||||
#define REG_DSI_28nm_PHY_TIMING_CTRL_11 0x0000016c
|
||||
#define DSI_28nm_PHY_TIMING_CTRL_11_TRIG3_CMD__MASK 0x000000ff
|
||||
#define DSI_28nm_PHY_TIMING_CTRL_11_TRIG3_CMD__SHIFT 0
|
||||
static inline uint32_t DSI_28nm_PHY_TIMING_CTRL_11_TRIG3_CMD(uint32_t val)
|
||||
{
|
||||
return ((val) << DSI_28nm_PHY_TIMING_CTRL_11_TRIG3_CMD__SHIFT) & DSI_28nm_PHY_TIMING_CTRL_11_TRIG3_CMD__MASK;
|
||||
}
|
||||
|
||||
#define REG_DSI_28nm_PHY_CTRL_0 0x00000170
|
||||
|
||||
#define REG_DSI_28nm_PHY_CTRL_1 0x00000174
|
||||
|
||||
#define REG_DSI_28nm_PHY_CTRL_2 0x00000178
|
||||
|
||||
#define REG_DSI_28nm_PHY_CTRL_3 0x0000017c
|
||||
|
||||
#define REG_DSI_28nm_PHY_CTRL_4 0x00000180
|
||||
|
||||
#define REG_DSI_28nm_PHY_STRENGTH_0 0x00000184
|
||||
|
||||
#define REG_DSI_28nm_PHY_STRENGTH_1 0x00000188
|
||||
|
||||
#define REG_DSI_28nm_PHY_BIST_CTRL_0 0x000001b4
|
||||
|
||||
#define REG_DSI_28nm_PHY_BIST_CTRL_1 0x000001b8
|
||||
|
||||
#define REG_DSI_28nm_PHY_BIST_CTRL_2 0x000001bc
|
||||
|
||||
#define REG_DSI_28nm_PHY_BIST_CTRL_3 0x000001c0
|
||||
|
||||
#define REG_DSI_28nm_PHY_BIST_CTRL_4 0x000001c4
|
||||
|
||||
#define REG_DSI_28nm_PHY_BIST_CTRL_5 0x000001c8
|
||||
|
||||
#define REG_DSI_28nm_PHY_GLBL_TEST_CTRL 0x000001d4
|
||||
|
||||
#define REG_DSI_28nm_PHY_LDO_CNTRL 0x000001dc
|
||||
|
||||
#define REG_DSI_28nm_PHY_REGULATOR_CTRL_0 0x00000000
|
||||
|
||||
#define REG_DSI_28nm_PHY_REGULATOR_CTRL_1 0x00000004
|
||||
|
||||
#define REG_DSI_28nm_PHY_REGULATOR_CTRL_2 0x00000008
|
||||
|
||||
#define REG_DSI_28nm_PHY_REGULATOR_CTRL_3 0x0000000c
|
||||
|
||||
#define REG_DSI_28nm_PHY_REGULATOR_CTRL_4 0x00000010
|
||||
|
||||
#define REG_DSI_28nm_PHY_REGULATOR_CTRL_5 0x00000014
|
||||
|
||||
#define REG_DSI_28nm_PHY_REGULATOR_CAL_PWR_CFG 0x00000018
|
||||
|
||||
|
||||
#endif /* DSI_XML */
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,705 @@
|
|||
/*
|
||||
* 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_kms.h"
|
||||
#include "dsi.h"
|
||||
|
||||
struct msm_dsi_manager {
|
||||
struct msm_dsi *dsi[DSI_MAX];
|
||||
|
||||
bool is_dual_panel;
|
||||
bool is_sync_needed;
|
||||
int master_panel_id;
|
||||
};
|
||||
|
||||
static struct msm_dsi_manager msm_dsim_glb;
|
||||
|
||||
#define IS_DUAL_PANEL() (msm_dsim_glb.is_dual_panel)
|
||||
#define IS_SYNC_NEEDED() (msm_dsim_glb.is_sync_needed)
|
||||
#define IS_MASTER_PANEL(id) (msm_dsim_glb.master_panel_id == id)
|
||||
|
||||
static inline struct msm_dsi *dsi_mgr_get_dsi(int id)
|
||||
{
|
||||
return msm_dsim_glb.dsi[id];
|
||||
}
|
||||
|
||||
static inline struct msm_dsi *dsi_mgr_get_other_dsi(int id)
|
||||
{
|
||||
return msm_dsim_glb.dsi[(id + 1) % DSI_MAX];
|
||||
}
|
||||
|
||||
static int dsi_mgr_parse_dual_panel(struct device_node *np, int id)
|
||||
{
|
||||
struct msm_dsi_manager *msm_dsim = &msm_dsim_glb;
|
||||
|
||||
/* We assume 2 dsi nodes have the same information of dual-panel and
|
||||
* sync-mode, and only one node specifies master in case of dual mode.
|
||||
*/
|
||||
if (!msm_dsim->is_dual_panel)
|
||||
msm_dsim->is_dual_panel = of_property_read_bool(
|
||||
np, "qcom,dual-panel-mode");
|
||||
|
||||
if (msm_dsim->is_dual_panel) {
|
||||
if (of_property_read_bool(np, "qcom,master-panel"))
|
||||
msm_dsim->master_panel_id = id;
|
||||
if (!msm_dsim->is_sync_needed)
|
||||
msm_dsim->is_sync_needed = of_property_read_bool(
|
||||
np, "qcom,sync-dual-panel");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dsi_connector {
|
||||
struct drm_connector base;
|
||||
int id;
|
||||
};
|
||||
|
||||
struct dsi_bridge {
|
||||
struct drm_bridge base;
|
||||
int id;
|
||||
};
|
||||
|
||||
#define to_dsi_connector(x) container_of(x, struct dsi_connector, base)
|
||||
#define to_dsi_bridge(x) container_of(x, struct dsi_bridge, base)
|
||||
|
||||
static inline int dsi_mgr_connector_get_id(struct drm_connector *connector)
|
||||
{
|
||||
struct dsi_connector *dsi_connector = to_dsi_connector(connector);
|
||||
return dsi_connector->id;
|
||||
}
|
||||
|
||||
static int dsi_mgr_bridge_get_id(struct drm_bridge *bridge)
|
||||
{
|
||||
struct dsi_bridge *dsi_bridge = to_dsi_bridge(bridge);
|
||||
return dsi_bridge->id;
|
||||
}
|
||||
|
||||
static enum drm_connector_status dsi_mgr_connector_detect(
|
||||
struct drm_connector *connector, bool force)
|
||||
{
|
||||
int id = dsi_mgr_connector_get_id(connector);
|
||||
struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
|
||||
struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id);
|
||||
struct msm_drm_private *priv = connector->dev->dev_private;
|
||||
struct msm_kms *kms = priv->kms;
|
||||
|
||||
DBG("id=%d", id);
|
||||
if (!msm_dsi->panel) {
|
||||
msm_dsi->panel = msm_dsi_host_get_panel(msm_dsi->host,
|
||||
&msm_dsi->panel_flags);
|
||||
|
||||
/* There is only 1 panel in the global panel list
|
||||
* for dual panel mode. Therefore slave dsi should get
|
||||
* the drm_panel instance from master dsi, and
|
||||
* keep using the panel flags got from the current DSI link.
|
||||
*/
|
||||
if (!msm_dsi->panel && IS_DUAL_PANEL() &&
|
||||
!IS_MASTER_PANEL(id) && other_dsi)
|
||||
msm_dsi->panel = msm_dsi_host_get_panel(
|
||||
other_dsi->host, NULL);
|
||||
|
||||
if (msm_dsi->panel && IS_DUAL_PANEL())
|
||||
drm_object_attach_property(&connector->base,
|
||||
connector->dev->mode_config.tile_property, 0);
|
||||
|
||||
/* Set split display info to kms once dual panel is connected
|
||||
* to both hosts
|
||||
*/
|
||||
if (msm_dsi->panel && IS_DUAL_PANEL() &&
|
||||
other_dsi && other_dsi->panel) {
|
||||
bool cmd_mode = !(msm_dsi->panel_flags &
|
||||
MIPI_DSI_MODE_VIDEO);
|
||||
struct drm_encoder *encoder = msm_dsi_get_encoder(
|
||||
dsi_mgr_get_dsi(DSI_ENCODER_MASTER));
|
||||
struct drm_encoder *slave_enc = msm_dsi_get_encoder(
|
||||
dsi_mgr_get_dsi(DSI_ENCODER_SLAVE));
|
||||
|
||||
if (kms->funcs->set_split_display)
|
||||
kms->funcs->set_split_display(kms, encoder,
|
||||
slave_enc, cmd_mode);
|
||||
else
|
||||
pr_err("mdp does not support dual panel\n");
|
||||
}
|
||||
}
|
||||
|
||||
return msm_dsi->panel ? connector_status_connected :
|
||||
connector_status_disconnected;
|
||||
}
|
||||
|
||||
static void dsi_mgr_connector_destroy(struct drm_connector *connector)
|
||||
{
|
||||
DBG("");
|
||||
drm_connector_unregister(connector);
|
||||
drm_connector_cleanup(connector);
|
||||
}
|
||||
|
||||
static void dsi_dual_connector_fix_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct drm_display_mode *mode, *m;
|
||||
|
||||
/* Only support left-right mode */
|
||||
list_for_each_entry_safe(mode, m, &connector->probed_modes, head) {
|
||||
mode->clock >>= 1;
|
||||
mode->hdisplay >>= 1;
|
||||
mode->hsync_start >>= 1;
|
||||
mode->hsync_end >>= 1;
|
||||
mode->htotal >>= 1;
|
||||
drm_mode_set_name(mode);
|
||||
}
|
||||
}
|
||||
|
||||
static int dsi_dual_connector_tile_init(
|
||||
struct drm_connector *connector, int id)
|
||||
{
|
||||
struct drm_display_mode *mode;
|
||||
/* Fake topology id */
|
||||
char topo_id[8] = {'M', 'S', 'M', 'D', 'U', 'D', 'S', 'I'};
|
||||
|
||||
if (connector->tile_group) {
|
||||
DBG("Tile property has been initialized");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Use the first mode only for now */
|
||||
mode = list_first_entry(&connector->probed_modes,
|
||||
struct drm_display_mode,
|
||||
head);
|
||||
if (!mode)
|
||||
return -EINVAL;
|
||||
|
||||
connector->tile_group = drm_mode_get_tile_group(
|
||||
connector->dev, topo_id);
|
||||
if (!connector->tile_group)
|
||||
connector->tile_group = drm_mode_create_tile_group(
|
||||
connector->dev, topo_id);
|
||||
if (!connector->tile_group) {
|
||||
pr_err("%s: failed to create tile group\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
connector->has_tile = true;
|
||||
connector->tile_is_single_monitor = true;
|
||||
|
||||
/* mode has been fixed */
|
||||
connector->tile_h_size = mode->hdisplay;
|
||||
connector->tile_v_size = mode->vdisplay;
|
||||
|
||||
/* Only support left-right mode */
|
||||
connector->num_h_tile = 2;
|
||||
connector->num_v_tile = 1;
|
||||
|
||||
connector->tile_v_loc = 0;
|
||||
connector->tile_h_loc = (id == DSI_RIGHT) ? 1 : 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dsi_mgr_connector_get_modes(struct drm_connector *connector)
|
||||
{
|
||||
int id = dsi_mgr_connector_get_id(connector);
|
||||
struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
|
||||
struct drm_panel *panel = msm_dsi->panel;
|
||||
int ret, num;
|
||||
|
||||
if (!panel)
|
||||
return 0;
|
||||
|
||||
/* Since we have 2 connectors, but only 1 drm_panel in dual DSI mode,
|
||||
* panel should not attach to any connector.
|
||||
* Only temporarily attach panel to the current connector here,
|
||||
* to let panel set mode to this connector.
|
||||
*/
|
||||
drm_panel_attach(panel, connector);
|
||||
num = drm_panel_get_modes(panel);
|
||||
drm_panel_detach(panel);
|
||||
if (!num)
|
||||
return 0;
|
||||
|
||||
if (IS_DUAL_PANEL()) {
|
||||
/* report half resolution to user */
|
||||
dsi_dual_connector_fix_modes(connector);
|
||||
ret = dsi_dual_connector_tile_init(connector, id);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = drm_mode_connector_set_tile_property(connector);
|
||||
if (ret) {
|
||||
pr_err("%s: set tile property failed, %d\n",
|
||||
__func__, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
static int dsi_mgr_connector_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
int id = dsi_mgr_connector_get_id(connector);
|
||||
struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
|
||||
struct drm_encoder *encoder = msm_dsi_get_encoder(msm_dsi);
|
||||
struct msm_drm_private *priv = connector->dev->dev_private;
|
||||
struct msm_kms *kms = priv->kms;
|
||||
long actual, requested;
|
||||
|
||||
DBG("");
|
||||
requested = 1000 * mode->clock;
|
||||
actual = kms->funcs->round_pixclk(kms, requested, encoder);
|
||||
|
||||
DBG("requested=%ld, actual=%ld", requested, actual);
|
||||
if (actual != requested)
|
||||
return MODE_CLOCK_RANGE;
|
||||
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
static struct drm_encoder *
|
||||
dsi_mgr_connector_best_encoder(struct drm_connector *connector)
|
||||
{
|
||||
int id = dsi_mgr_connector_get_id(connector);
|
||||
struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
|
||||
|
||||
DBG("");
|
||||
return msm_dsi_get_encoder(msm_dsi);
|
||||
}
|
||||
|
||||
static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
|
||||
{
|
||||
int id = dsi_mgr_bridge_get_id(bridge);
|
||||
struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
|
||||
struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
|
||||
struct mipi_dsi_host *host = msm_dsi->host;
|
||||
struct drm_panel *panel = msm_dsi->panel;
|
||||
bool is_dual_panel = IS_DUAL_PANEL();
|
||||
int ret;
|
||||
|
||||
DBG("id=%d", id);
|
||||
if (!panel || (is_dual_panel && (DSI_1 == id)))
|
||||
return;
|
||||
|
||||
ret = msm_dsi_host_power_on(host);
|
||||
if (ret) {
|
||||
pr_err("%s: power on host %d failed, %d\n", __func__, id, ret);
|
||||
goto host_on_fail;
|
||||
}
|
||||
|
||||
if (is_dual_panel && msm_dsi1) {
|
||||
ret = msm_dsi_host_power_on(msm_dsi1->host);
|
||||
if (ret) {
|
||||
pr_err("%s: power on host1 failed, %d\n",
|
||||
__func__, ret);
|
||||
goto host1_on_fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* Always call panel functions once, because even for dual panels,
|
||||
* there is only one drm_panel instance.
|
||||
*/
|
||||
ret = drm_panel_prepare(panel);
|
||||
if (ret) {
|
||||
pr_err("%s: prepare panel %d failed, %d\n", __func__, id, ret);
|
||||
goto panel_prep_fail;
|
||||
}
|
||||
|
||||
ret = msm_dsi_host_enable(host);
|
||||
if (ret) {
|
||||
pr_err("%s: enable host %d failed, %d\n", __func__, id, ret);
|
||||
goto host_en_fail;
|
||||
}
|
||||
|
||||
if (is_dual_panel && msm_dsi1) {
|
||||
ret = msm_dsi_host_enable(msm_dsi1->host);
|
||||
if (ret) {
|
||||
pr_err("%s: enable host1 failed, %d\n", __func__, ret);
|
||||
goto host1_en_fail;
|
||||
}
|
||||
}
|
||||
|
||||
ret = drm_panel_enable(panel);
|
||||
if (ret) {
|
||||
pr_err("%s: enable panel %d failed, %d\n", __func__, id, ret);
|
||||
goto panel_en_fail;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
panel_en_fail:
|
||||
if (is_dual_panel && msm_dsi1)
|
||||
msm_dsi_host_disable(msm_dsi1->host);
|
||||
host1_en_fail:
|
||||
msm_dsi_host_disable(host);
|
||||
host_en_fail:
|
||||
drm_panel_unprepare(panel);
|
||||
panel_prep_fail:
|
||||
if (is_dual_panel && msm_dsi1)
|
||||
msm_dsi_host_power_off(msm_dsi1->host);
|
||||
host1_on_fail:
|
||||
msm_dsi_host_power_off(host);
|
||||
host_on_fail:
|
||||
return;
|
||||
}
|
||||
|
||||
static void dsi_mgr_bridge_enable(struct drm_bridge *bridge)
|
||||
{
|
||||
DBG("");
|
||||
}
|
||||
|
||||
static void dsi_mgr_bridge_disable(struct drm_bridge *bridge)
|
||||
{
|
||||
DBG("");
|
||||
}
|
||||
|
||||
static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
|
||||
{
|
||||
int id = dsi_mgr_bridge_get_id(bridge);
|
||||
struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
|
||||
struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
|
||||
struct mipi_dsi_host *host = msm_dsi->host;
|
||||
struct drm_panel *panel = msm_dsi->panel;
|
||||
bool is_dual_panel = IS_DUAL_PANEL();
|
||||
int ret;
|
||||
|
||||
DBG("id=%d", id);
|
||||
|
||||
if (!panel || (is_dual_panel && (DSI_1 == id)))
|
||||
return;
|
||||
|
||||
ret = drm_panel_disable(panel);
|
||||
if (ret)
|
||||
pr_err("%s: Panel %d OFF failed, %d\n", __func__, id, ret);
|
||||
|
||||
ret = msm_dsi_host_disable(host);
|
||||
if (ret)
|
||||
pr_err("%s: host %d disable failed, %d\n", __func__, id, ret);
|
||||
|
||||
if (is_dual_panel && msm_dsi1) {
|
||||
ret = msm_dsi_host_disable(msm_dsi1->host);
|
||||
if (ret)
|
||||
pr_err("%s: host1 disable failed, %d\n", __func__, ret);
|
||||
}
|
||||
|
||||
ret = drm_panel_unprepare(panel);
|
||||
if (ret)
|
||||
pr_err("%s: Panel %d unprepare failed,%d\n", __func__, id, ret);
|
||||
|
||||
ret = msm_dsi_host_power_off(host);
|
||||
if (ret)
|
||||
pr_err("%s: host %d power off failed,%d\n", __func__, id, ret);
|
||||
|
||||
if (is_dual_panel && msm_dsi1) {
|
||||
ret = msm_dsi_host_power_off(msm_dsi1->host);
|
||||
if (ret)
|
||||
pr_err("%s: host1 power off failed, %d\n",
|
||||
__func__, ret);
|
||||
}
|
||||
}
|
||||
|
||||
static void dsi_mgr_bridge_mode_set(struct drm_bridge *bridge,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
int id = dsi_mgr_bridge_get_id(bridge);
|
||||
struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
|
||||
struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id);
|
||||
struct mipi_dsi_host *host = msm_dsi->host;
|
||||
bool is_dual_panel = IS_DUAL_PANEL();
|
||||
|
||||
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);
|
||||
|
||||
if (is_dual_panel && (DSI_1 == id))
|
||||
return;
|
||||
|
||||
msm_dsi_host_set_display_mode(host, adjusted_mode);
|
||||
if (is_dual_panel && other_dsi)
|
||||
msm_dsi_host_set_display_mode(other_dsi->host, adjusted_mode);
|
||||
}
|
||||
|
||||
static const struct drm_connector_funcs dsi_mgr_connector_funcs = {
|
||||
.dpms = drm_atomic_helper_connector_dpms,
|
||||
.detect = dsi_mgr_connector_detect,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.destroy = dsi_mgr_connector_destroy,
|
||||
.reset = drm_atomic_helper_connector_reset,
|
||||
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
|
||||
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
|
||||
};
|
||||
|
||||
static const struct drm_connector_helper_funcs dsi_mgr_conn_helper_funcs = {
|
||||
.get_modes = dsi_mgr_connector_get_modes,
|
||||
.mode_valid = dsi_mgr_connector_mode_valid,
|
||||
.best_encoder = dsi_mgr_connector_best_encoder,
|
||||
};
|
||||
|
||||
static const struct drm_bridge_funcs dsi_mgr_bridge_funcs = {
|
||||
.pre_enable = dsi_mgr_bridge_pre_enable,
|
||||
.enable = dsi_mgr_bridge_enable,
|
||||
.disable = dsi_mgr_bridge_disable,
|
||||
.post_disable = dsi_mgr_bridge_post_disable,
|
||||
.mode_set = dsi_mgr_bridge_mode_set,
|
||||
};
|
||||
|
||||
/* initialize connector */
|
||||
struct drm_connector *msm_dsi_manager_connector_init(u8 id)
|
||||
{
|
||||
struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
|
||||
struct drm_connector *connector = NULL;
|
||||
struct dsi_connector *dsi_connector;
|
||||
int ret;
|
||||
|
||||
dsi_connector = devm_kzalloc(msm_dsi->dev->dev,
|
||||
sizeof(*dsi_connector), GFP_KERNEL);
|
||||
if (!dsi_connector) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
dsi_connector->id = id;
|
||||
|
||||
connector = &dsi_connector->base;
|
||||
|
||||
ret = drm_connector_init(msm_dsi->dev, connector,
|
||||
&dsi_mgr_connector_funcs, DRM_MODE_CONNECTOR_DSI);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
drm_connector_helper_add(connector, &dsi_mgr_conn_helper_funcs);
|
||||
|
||||
/* Enable HPD to let hpd event is handled
|
||||
* when panel is attached to the host.
|
||||
*/
|
||||
connector->polled = DRM_CONNECTOR_POLL_HPD;
|
||||
|
||||
/* Display driver doesn't support interlace now. */
|
||||
connector->interlace_allowed = 0;
|
||||
connector->doublescan_allowed = 0;
|
||||
|
||||
ret = drm_connector_register(connector);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
return connector;
|
||||
|
||||
fail:
|
||||
if (connector)
|
||||
dsi_mgr_connector_destroy(connector);
|
||||
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
/* initialize bridge */
|
||||
struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
|
||||
{
|
||||
struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
|
||||
struct drm_bridge *bridge = NULL;
|
||||
struct dsi_bridge *dsi_bridge;
|
||||
int ret;
|
||||
|
||||
dsi_bridge = devm_kzalloc(msm_dsi->dev->dev,
|
||||
sizeof(*dsi_bridge), GFP_KERNEL);
|
||||
if (!dsi_bridge) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
dsi_bridge->id = id;
|
||||
|
||||
bridge = &dsi_bridge->base;
|
||||
bridge->funcs = &dsi_mgr_bridge_funcs;
|
||||
|
||||
ret = drm_bridge_attach(msm_dsi->dev, bridge);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
return bridge;
|
||||
|
||||
fail:
|
||||
if (bridge)
|
||||
msm_dsi_manager_bridge_destroy(bridge);
|
||||
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
void msm_dsi_manager_bridge_destroy(struct drm_bridge *bridge)
|
||||
{
|
||||
}
|
||||
|
||||
int msm_dsi_manager_phy_enable(int id,
|
||||
const unsigned long bit_rate, const unsigned long esc_rate,
|
||||
u32 *clk_pre, u32 *clk_post)
|
||||
{
|
||||
struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
|
||||
struct msm_dsi_phy *phy = msm_dsi->phy;
|
||||
int ret;
|
||||
|
||||
ret = msm_dsi_phy_enable(phy, IS_DUAL_PANEL(), bit_rate, esc_rate);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
msm_dsi->phy_enabled = true;
|
||||
msm_dsi_phy_get_clk_pre_post(phy, clk_pre, clk_post);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void msm_dsi_manager_phy_disable(int id)
|
||||
{
|
||||
struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
|
||||
struct msm_dsi *mdsi = dsi_mgr_get_dsi(DSI_CLOCK_MASTER);
|
||||
struct msm_dsi *sdsi = dsi_mgr_get_dsi(DSI_CLOCK_SLAVE);
|
||||
struct msm_dsi_phy *phy = msm_dsi->phy;
|
||||
|
||||
/* disable DSI phy
|
||||
* In dual-dsi configuration, the phy should be disabled for the
|
||||
* first controller only when the second controller is disabled.
|
||||
*/
|
||||
msm_dsi->phy_enabled = false;
|
||||
if (IS_DUAL_PANEL() && mdsi && sdsi) {
|
||||
if (!mdsi->phy_enabled && !sdsi->phy_enabled) {
|
||||
msm_dsi_phy_disable(sdsi->phy);
|
||||
msm_dsi_phy_disable(mdsi->phy);
|
||||
}
|
||||
} else {
|
||||
msm_dsi_phy_disable(phy);
|
||||
}
|
||||
}
|
||||
|
||||
int msm_dsi_manager_cmd_xfer(int id, const struct mipi_dsi_msg *msg)
|
||||
{
|
||||
struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
|
||||
struct msm_dsi *msm_dsi0 = dsi_mgr_get_dsi(DSI_0);
|
||||
struct mipi_dsi_host *host = msm_dsi->host;
|
||||
bool is_read = (msg->rx_buf && msg->rx_len);
|
||||
bool need_sync = (IS_SYNC_NEEDED() && !is_read);
|
||||
int ret;
|
||||
|
||||
if (!msg->tx_buf || !msg->tx_len)
|
||||
return 0;
|
||||
|
||||
/* In dual master case, panel requires the same commands sent to
|
||||
* both DSI links. Host issues the command trigger to both links
|
||||
* when DSI_1 calls the cmd transfer function, no matter it happens
|
||||
* before or after DSI_0 cmd transfer.
|
||||
*/
|
||||
if (need_sync && (id == DSI_0))
|
||||
return is_read ? msg->rx_len : msg->tx_len;
|
||||
|
||||
if (need_sync && msm_dsi0) {
|
||||
ret = msm_dsi_host_xfer_prepare(msm_dsi0->host, msg);
|
||||
if (ret) {
|
||||
pr_err("%s: failed to prepare non-trigger host, %d\n",
|
||||
__func__, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
ret = msm_dsi_host_xfer_prepare(host, msg);
|
||||
if (ret) {
|
||||
pr_err("%s: failed to prepare host, %d\n", __func__, ret);
|
||||
goto restore_host0;
|
||||
}
|
||||
|
||||
ret = is_read ? msm_dsi_host_cmd_rx(host, msg) :
|
||||
msm_dsi_host_cmd_tx(host, msg);
|
||||
|
||||
msm_dsi_host_xfer_restore(host, msg);
|
||||
|
||||
restore_host0:
|
||||
if (need_sync && msm_dsi0)
|
||||
msm_dsi_host_xfer_restore(msm_dsi0->host, msg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 iova, u32 len)
|
||||
{
|
||||
struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
|
||||
struct msm_dsi *msm_dsi0 = dsi_mgr_get_dsi(DSI_0);
|
||||
struct mipi_dsi_host *host = msm_dsi->host;
|
||||
|
||||
if (IS_SYNC_NEEDED() && (id == DSI_0))
|
||||
return false;
|
||||
|
||||
if (IS_SYNC_NEEDED() && msm_dsi0)
|
||||
msm_dsi_host_cmd_xfer_commit(msm_dsi0->host, iova, len);
|
||||
|
||||
msm_dsi_host_cmd_xfer_commit(host, iova, len);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int msm_dsi_manager_register(struct msm_dsi *msm_dsi)
|
||||
{
|
||||
struct msm_dsi_manager *msm_dsim = &msm_dsim_glb;
|
||||
int id = msm_dsi->id;
|
||||
struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id);
|
||||
int ret;
|
||||
|
||||
if (id > DSI_MAX) {
|
||||
pr_err("%s: invalid id %d\n", __func__, id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (msm_dsim->dsi[id]) {
|
||||
pr_err("%s: dsi%d already registered\n", __func__, id);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
msm_dsim->dsi[id] = msm_dsi;
|
||||
|
||||
ret = dsi_mgr_parse_dual_panel(msm_dsi->pdev->dev.of_node, id);
|
||||
if (ret) {
|
||||
pr_err("%s: failed to parse dual panel info\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!IS_DUAL_PANEL()) {
|
||||
ret = msm_dsi_host_register(msm_dsi->host, true);
|
||||
} else if (!other_dsi) {
|
||||
return 0;
|
||||
} else {
|
||||
struct msm_dsi *mdsi = IS_MASTER_PANEL(id) ?
|
||||
msm_dsi : other_dsi;
|
||||
struct msm_dsi *sdsi = IS_MASTER_PANEL(id) ?
|
||||
other_dsi : msm_dsi;
|
||||
/* Register slave host first, so that slave DSI device
|
||||
* has a chance to probe, and do not block the master
|
||||
* DSI device's probe.
|
||||
* Also, do not check defer for the slave host,
|
||||
* because only master DSI device adds the panel to global
|
||||
* panel list. The panel's device is the master DSI device.
|
||||
*/
|
||||
ret = msm_dsi_host_register(sdsi->host, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = msm_dsi_host_register(mdsi->host, true);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void msm_dsi_manager_unregister(struct msm_dsi *msm_dsi)
|
||||
{
|
||||
struct msm_dsi_manager *msm_dsim = &msm_dsim_glb;
|
||||
|
||||
if (msm_dsi->host)
|
||||
msm_dsi_host_unregister(msm_dsi->host);
|
||||
msm_dsim->dsi[msm_dsi->id] = NULL;
|
||||
}
|
||||
|
|
@ -0,0 +1,352 @@
|
|||
/*
|
||||
* 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 "dsi.h"
|
||||
#include "dsi.xml.h"
|
||||
|
||||
#define dsi_phy_read(offset) msm_readl((offset))
|
||||
#define dsi_phy_write(offset, data) msm_writel((data), (offset))
|
||||
|
||||
struct dsi_dphy_timing {
|
||||
u32 clk_pre;
|
||||
u32 clk_post;
|
||||
u32 clk_zero;
|
||||
u32 clk_trail;
|
||||
u32 clk_prepare;
|
||||
u32 hs_exit;
|
||||
u32 hs_zero;
|
||||
u32 hs_prepare;
|
||||
u32 hs_trail;
|
||||
u32 hs_rqst;
|
||||
u32 ta_go;
|
||||
u32 ta_sure;
|
||||
u32 ta_get;
|
||||
};
|
||||
|
||||
struct msm_dsi_phy {
|
||||
void __iomem *base;
|
||||
void __iomem *reg_base;
|
||||
int id;
|
||||
struct dsi_dphy_timing timing;
|
||||
int (*enable)(struct msm_dsi_phy *phy, bool is_dual_panel,
|
||||
const unsigned long bit_rate, const unsigned long esc_rate);
|
||||
int (*disable)(struct msm_dsi_phy *phy);
|
||||
};
|
||||
|
||||
#define S_DIV_ROUND_UP(n, d) \
|
||||
(((n) >= 0) ? (((n) + (d) - 1) / (d)) : (((n) - (d) + 1) / (d)))
|
||||
|
||||
static inline s32 linear_inter(s32 tmax, s32 tmin, s32 percent,
|
||||
s32 min_result, bool even)
|
||||
{
|
||||
s32 v;
|
||||
v = (tmax - tmin) * percent;
|
||||
v = S_DIV_ROUND_UP(v, 100) + tmin;
|
||||
if (even && (v & 0x1))
|
||||
return max_t(s32, min_result, v - 1);
|
||||
else
|
||||
return max_t(s32, min_result, v);
|
||||
}
|
||||
|
||||
static void dsi_dphy_timing_calc_clk_zero(struct dsi_dphy_timing *timing,
|
||||
s32 ui, s32 coeff, s32 pcnt)
|
||||
{
|
||||
s32 tmax, tmin, clk_z;
|
||||
s32 temp;
|
||||
|
||||
/* reset */
|
||||
temp = 300 * coeff - ((timing->clk_prepare >> 1) + 1) * 2 * ui;
|
||||
tmin = S_DIV_ROUND_UP(temp, ui) - 2;
|
||||
if (tmin > 255) {
|
||||
tmax = 511;
|
||||
clk_z = linear_inter(2 * tmin, tmin, pcnt, 0, true);
|
||||
} else {
|
||||
tmax = 255;
|
||||
clk_z = linear_inter(tmax, tmin, pcnt, 0, true);
|
||||
}
|
||||
|
||||
/* adjust */
|
||||
temp = (timing->hs_rqst + timing->clk_prepare + clk_z) & 0x7;
|
||||
timing->clk_zero = clk_z + 8 - temp;
|
||||
}
|
||||
|
||||
static int dsi_dphy_timing_calc(struct dsi_dphy_timing *timing,
|
||||
const unsigned long bit_rate, const unsigned long esc_rate)
|
||||
{
|
||||
s32 ui, lpx;
|
||||
s32 tmax, tmin;
|
||||
s32 pcnt0 = 10;
|
||||
s32 pcnt1 = (bit_rate > 1200000000) ? 15 : 10;
|
||||
s32 pcnt2 = 10;
|
||||
s32 pcnt3 = (bit_rate > 180000000) ? 10 : 40;
|
||||
s32 coeff = 1000; /* Precision, should avoid overflow */
|
||||
s32 temp;
|
||||
|
||||
if (!bit_rate || !esc_rate)
|
||||
return -EINVAL;
|
||||
|
||||
ui = mult_frac(NSEC_PER_MSEC, coeff, bit_rate / 1000);
|
||||
lpx = mult_frac(NSEC_PER_MSEC, coeff, esc_rate / 1000);
|
||||
|
||||
tmax = S_DIV_ROUND_UP(95 * coeff, ui) - 2;
|
||||
tmin = S_DIV_ROUND_UP(38 * coeff, ui) - 2;
|
||||
timing->clk_prepare = linear_inter(tmax, tmin, pcnt0, 0, true);
|
||||
|
||||
temp = lpx / ui;
|
||||
if (temp & 0x1)
|
||||
timing->hs_rqst = temp;
|
||||
else
|
||||
timing->hs_rqst = max_t(s32, 0, temp - 2);
|
||||
|
||||
/* Calculate clk_zero after clk_prepare and hs_rqst */
|
||||
dsi_dphy_timing_calc_clk_zero(timing, ui, coeff, pcnt2);
|
||||
|
||||
temp = 105 * coeff + 12 * ui - 20 * coeff;
|
||||
tmax = S_DIV_ROUND_UP(temp, ui) - 2;
|
||||
tmin = S_DIV_ROUND_UP(60 * coeff, ui) - 2;
|
||||
timing->clk_trail = linear_inter(tmax, tmin, pcnt3, 0, true);
|
||||
|
||||
temp = 85 * coeff + 6 * ui;
|
||||
tmax = S_DIV_ROUND_UP(temp, ui) - 2;
|
||||
temp = 40 * coeff + 4 * ui;
|
||||
tmin = S_DIV_ROUND_UP(temp, ui) - 2;
|
||||
timing->hs_prepare = linear_inter(tmax, tmin, pcnt1, 0, true);
|
||||
|
||||
tmax = 255;
|
||||
temp = ((timing->hs_prepare >> 1) + 1) * 2 * ui + 2 * ui;
|
||||
temp = 145 * coeff + 10 * ui - temp;
|
||||
tmin = S_DIV_ROUND_UP(temp, ui) - 2;
|
||||
timing->hs_zero = linear_inter(tmax, tmin, pcnt2, 24, true);
|
||||
|
||||
temp = 105 * coeff + 12 * ui - 20 * coeff;
|
||||
tmax = S_DIV_ROUND_UP(temp, ui) - 2;
|
||||
temp = 60 * coeff + 4 * ui;
|
||||
tmin = DIV_ROUND_UP(temp, ui) - 2;
|
||||
timing->hs_trail = linear_inter(tmax, tmin, pcnt3, 0, true);
|
||||
|
||||
tmax = 255;
|
||||
tmin = S_DIV_ROUND_UP(100 * coeff, ui) - 2;
|
||||
timing->hs_exit = linear_inter(tmax, tmin, pcnt2, 0, true);
|
||||
|
||||
tmax = 63;
|
||||
temp = ((timing->hs_exit >> 1) + 1) * 2 * ui;
|
||||
temp = 60 * coeff + 52 * ui - 24 * ui - temp;
|
||||
tmin = S_DIV_ROUND_UP(temp, 8 * ui) - 1;
|
||||
timing->clk_post = linear_inter(tmax, tmin, pcnt2, 0, false);
|
||||
|
||||
tmax = 63;
|
||||
temp = ((timing->clk_prepare >> 1) + 1) * 2 * ui;
|
||||
temp += ((timing->clk_zero >> 1) + 1) * 2 * ui;
|
||||
temp += 8 * ui + lpx;
|
||||
tmin = S_DIV_ROUND_UP(temp, 8 * ui) - 1;
|
||||
if (tmin > tmax) {
|
||||
temp = linear_inter(2 * tmax, tmin, pcnt2, 0, false) >> 1;
|
||||
timing->clk_pre = temp >> 1;
|
||||
temp = (2 * tmax - tmin) * pcnt2;
|
||||
} else {
|
||||
timing->clk_pre = linear_inter(tmax, tmin, pcnt2, 0, false);
|
||||
}
|
||||
|
||||
timing->ta_go = 3;
|
||||
timing->ta_sure = 0;
|
||||
timing->ta_get = 4;
|
||||
|
||||
DBG("PHY timings: %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",
|
||||
timing->clk_pre, timing->clk_post, timing->clk_zero,
|
||||
timing->clk_trail, timing->clk_prepare, timing->hs_exit,
|
||||
timing->hs_zero, timing->hs_prepare, timing->hs_trail,
|
||||
timing->hs_rqst);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dsi_28nm_phy_regulator_ctrl(struct msm_dsi_phy *phy, bool enable)
|
||||
{
|
||||
void __iomem *base = phy->reg_base;
|
||||
|
||||
if (!enable) {
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CAL_PWR_CFG, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_0, 0x0);
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CAL_PWR_CFG, 1);
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_5, 0);
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_3, 0);
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_2, 0x3);
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_1, 0x9);
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_0, 0x7);
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_4, 0x20);
|
||||
}
|
||||
|
||||
static int dsi_28nm_phy_enable(struct msm_dsi_phy *phy, bool is_dual_panel,
|
||||
const unsigned long bit_rate, const unsigned long esc_rate)
|
||||
{
|
||||
struct dsi_dphy_timing *timing = &phy->timing;
|
||||
int i;
|
||||
void __iomem *base = phy->base;
|
||||
|
||||
DBG("");
|
||||
|
||||
if (dsi_dphy_timing_calc(timing, bit_rate, esc_rate)) {
|
||||
pr_err("%s: D-PHY timing calculation failed\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_STRENGTH_0, 0xff);
|
||||
|
||||
dsi_28nm_phy_regulator_ctrl(phy, true);
|
||||
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_LDO_CNTRL, 0x00);
|
||||
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_0,
|
||||
DSI_28nm_PHY_TIMING_CTRL_0_CLK_ZERO(timing->clk_zero));
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_1,
|
||||
DSI_28nm_PHY_TIMING_CTRL_1_CLK_TRAIL(timing->clk_trail));
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_2,
|
||||
DSI_28nm_PHY_TIMING_CTRL_2_CLK_PREPARE(timing->clk_prepare));
|
||||
if (timing->clk_zero & BIT(8))
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_3,
|
||||
DSI_28nm_PHY_TIMING_CTRL_3_CLK_ZERO_8);
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_4,
|
||||
DSI_28nm_PHY_TIMING_CTRL_4_HS_EXIT(timing->hs_exit));
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_5,
|
||||
DSI_28nm_PHY_TIMING_CTRL_5_HS_ZERO(timing->hs_zero));
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_6,
|
||||
DSI_28nm_PHY_TIMING_CTRL_6_HS_PREPARE(timing->hs_prepare));
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_7,
|
||||
DSI_28nm_PHY_TIMING_CTRL_7_HS_TRAIL(timing->hs_trail));
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_8,
|
||||
DSI_28nm_PHY_TIMING_CTRL_8_HS_RQST(timing->hs_rqst));
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_9,
|
||||
DSI_28nm_PHY_TIMING_CTRL_9_TA_GO(timing->ta_go) |
|
||||
DSI_28nm_PHY_TIMING_CTRL_9_TA_SURE(timing->ta_sure));
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_10,
|
||||
DSI_28nm_PHY_TIMING_CTRL_10_TA_GET(timing->ta_get));
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_11,
|
||||
DSI_28nm_PHY_TIMING_CTRL_11_TRIG3_CMD(0));
|
||||
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_CTRL_1, 0x00);
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_CTRL_0, 0x5f);
|
||||
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_STRENGTH_1, 0x6);
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_0(i), 0);
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_1(i), 0);
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_2(i), 0);
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_3(i), 0);
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_LN_TEST_DATAPATH(i), 0);
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_LN_DEBUG_SEL(i), 0);
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_LN_TEST_STR_0(i), 0x1);
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_LN_TEST_STR_1(i), 0x97);
|
||||
}
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(0), 0);
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(1), 0x5);
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(2), 0xa);
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(3), 0xf);
|
||||
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_CFG_1, 0xc0);
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_TEST_STR0, 0x1);
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_TEST_STR1, 0xbb);
|
||||
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_CTRL_0, 0x5f);
|
||||
|
||||
if (is_dual_panel && (phy->id != DSI_CLOCK_MASTER))
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_GLBL_TEST_CTRL, 0x00);
|
||||
else
|
||||
dsi_phy_write(base + REG_DSI_28nm_PHY_GLBL_TEST_CTRL, 0x01);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dsi_28nm_phy_disable(struct msm_dsi_phy *phy)
|
||||
{
|
||||
dsi_phy_write(phy->base + REG_DSI_28nm_PHY_CTRL_0, 0);
|
||||
dsi_28nm_phy_regulator_ctrl(phy, false);
|
||||
|
||||
/*
|
||||
* Wait for the registers writes to complete in order to
|
||||
* ensure that the phy is completely disabled
|
||||
*/
|
||||
wmb();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define dsi_phy_func_init(name) \
|
||||
do { \
|
||||
phy->enable = dsi_##name##_phy_enable; \
|
||||
phy->disable = dsi_##name##_phy_disable; \
|
||||
} while (0)
|
||||
|
||||
struct msm_dsi_phy *msm_dsi_phy_init(struct platform_device *pdev,
|
||||
enum msm_dsi_phy_type type, int id)
|
||||
{
|
||||
struct msm_dsi_phy *phy;
|
||||
|
||||
phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
|
||||
if (!phy)
|
||||
return NULL;
|
||||
|
||||
phy->base = msm_ioremap(pdev, "dsi_phy", "DSI_PHY");
|
||||
if (IS_ERR_OR_NULL(phy->base)) {
|
||||
pr_err("%s: failed to map phy base\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
phy->reg_base = msm_ioremap(pdev, "dsi_phy_regulator", "DSI_PHY_REG");
|
||||
if (IS_ERR_OR_NULL(phy->reg_base)) {
|
||||
pr_err("%s: failed to map phy regulator base\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case MSM_DSI_PHY_28NM:
|
||||
dsi_phy_func_init(28nm);
|
||||
break;
|
||||
default:
|
||||
pr_err("%s: unsupported type, %d\n", __func__, type);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
phy->id = id;
|
||||
|
||||
return phy;
|
||||
}
|
||||
|
||||
int msm_dsi_phy_enable(struct msm_dsi_phy *phy, bool is_dual_panel,
|
||||
const unsigned long bit_rate, const unsigned long esc_rate)
|
||||
{
|
||||
if (!phy || !phy->enable)
|
||||
return -EINVAL;
|
||||
return phy->enable(phy, is_dual_panel, bit_rate, esc_rate);
|
||||
}
|
||||
|
||||
int msm_dsi_phy_disable(struct msm_dsi_phy *phy)
|
||||
{
|
||||
if (!phy || !phy->disable)
|
||||
return -EINVAL;
|
||||
return phy->disable(phy);
|
||||
}
|
||||
|
||||
void msm_dsi_phy_get_clk_pre_post(struct msm_dsi_phy *phy,
|
||||
u32 *clk_pre, u32 *clk_post)
|
||||
{
|
||||
if (!phy)
|
||||
return;
|
||||
if (clk_pre)
|
||||
*clk_pre = phy->timing.clk_pre;
|
||||
if (clk_post)
|
||||
*clk_post = phy->timing.clk_post;
|
||||
}
|
||||
|
|
@ -53,6 +53,23 @@ struct pll_rate {
|
|||
|
||||
/* NOTE: keep sorted highest freq to lowest: */
|
||||
static const struct pll_rate freqtbl[] = {
|
||||
{ 154000000, {
|
||||
{ 0x08, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
|
||||
{ 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
|
||||
{ 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
|
||||
{ 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
|
||||
{ 0x03, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
|
||||
{ 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
|
||||
{ 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 },
|
||||
{ 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
|
||||
{ 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
|
||||
{ 0x0d, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
|
||||
{ 0x4d, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
|
||||
{ 0x5e, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
|
||||
{ 0x42, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
|
||||
{ 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
|
||||
{ 0, 0 } }
|
||||
},
|
||||
/* 1080p60/1080p50 case */
|
||||
{ 148500000, {
|
||||
{ 0x02, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
|
||||
|
@ -112,6 +129,23 @@ static const struct pll_rate freqtbl[] = {
|
|||
{ 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
|
||||
{ 0, 0 } }
|
||||
},
|
||||
{ 74176000, {
|
||||
{ 0x18, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
|
||||
{ 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
|
||||
{ 0xf9, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG1 },
|
||||
{ 0xe5, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG0 },
|
||||
{ 0x02, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG1 },
|
||||
{ 0x3b, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG2 },
|
||||
{ 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG3 },
|
||||
{ 0x86, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG4 },
|
||||
{ 0x00, REG_HDMI_8960_PHY_PLL_VCOCAL_CFG5 },
|
||||
{ 0x0c, REG_HDMI_8960_PHY_PLL_SDM_CFG0 },
|
||||
{ 0x4c, REG_HDMI_8960_PHY_PLL_SDM_CFG1 },
|
||||
{ 0x7d, REG_HDMI_8960_PHY_PLL_SDM_CFG2 },
|
||||
{ 0xbc, REG_HDMI_8960_PHY_PLL_SDM_CFG3 },
|
||||
{ 0x00, REG_HDMI_8960_PHY_PLL_SDM_CFG4 },
|
||||
{ 0, 0 } }
|
||||
},
|
||||
{ 65000000, {
|
||||
{ 0x18, REG_HDMI_8960_PHY_PLL_REFCLK_CFG },
|
||||
{ 0x20, REG_HDMI_8960_PHY_PLL_LOOP_FLT_CFG0 },
|
||||
|
|
|
@ -8,9 +8,9 @@ http://github.com/freedreno/envytools/
|
|||
git clone https://github.com/freedreno/envytools.git
|
||||
|
||||
The rules-ng-ng source files this header was generated from are:
|
||||
- /local/mnt2/workspace2/sviau/envytools/rnndb/mdp/mdp5.xml ( 27229 bytes, from 2015-02-10 17:00:41)
|
||||
- /local/mnt2/workspace2/sviau/envytools/rnndb/mdp/mdp5.xml ( 29312 bytes, from 2015-03-23 21:18:48)
|
||||
- /local/mnt2/workspace2/sviau/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2014-06-02 18:31:15)
|
||||
- /local/mnt2/workspace2/sviau/envytools/rnndb/mdp/mdp_common.xml ( 2357 bytes, from 2015-01-23 16:20:19)
|
||||
- /local/mnt2/workspace2/sviau/envytools/rnndb/mdp/mdp_common.xml ( 2357 bytes, from 2015-03-23 20:38:49)
|
||||
|
||||
Copyright (C) 2013-2015 by the following authors:
|
||||
- Rob Clark <robdclark@gmail.com> (robclark)
|
||||
|
@ -37,11 +37,14 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
*/
|
||||
|
||||
|
||||
enum mdp5_intf {
|
||||
enum mdp5_intf_type {
|
||||
INTF_DISABLED = 0,
|
||||
INTF_DSI = 1,
|
||||
INTF_HDMI = 3,
|
||||
INTF_LCDC = 5,
|
||||
INTF_eDP = 9,
|
||||
INTF_VIRTUAL = 100,
|
||||
INTF_WB = 101,
|
||||
};
|
||||
|
||||
enum mdp5_intfnum {
|
||||
|
@ -67,11 +70,11 @@ enum mdp5_pipe {
|
|||
|
||||
enum mdp5_ctl_mode {
|
||||
MODE_NONE = 0,
|
||||
MODE_ROT0 = 1,
|
||||
MODE_ROT1 = 2,
|
||||
MODE_WB0 = 3,
|
||||
MODE_WB1 = 4,
|
||||
MODE_WFD = 5,
|
||||
MODE_WB_0_BLOCK = 1,
|
||||
MODE_WB_1_BLOCK = 2,
|
||||
MODE_WB_0_LINE = 3,
|
||||
MODE_WB_1_LINE = 4,
|
||||
MODE_WB_2_LINE = 5,
|
||||
};
|
||||
|
||||
enum mdp5_pack_3d {
|
||||
|
@ -94,33 +97,6 @@ enum mdp5_pipe_bwc {
|
|||
BWC_Q_MED = 2,
|
||||
};
|
||||
|
||||
enum mdp5_client_id {
|
||||
CID_UNUSED = 0,
|
||||
CID_VIG0_Y = 1,
|
||||
CID_VIG0_CR = 2,
|
||||
CID_VIG0_CB = 3,
|
||||
CID_VIG1_Y = 4,
|
||||
CID_VIG1_CR = 5,
|
||||
CID_VIG1_CB = 6,
|
||||
CID_VIG2_Y = 7,
|
||||
CID_VIG2_CR = 8,
|
||||
CID_VIG2_CB = 9,
|
||||
CID_DMA0_Y = 10,
|
||||
CID_DMA0_CR = 11,
|
||||
CID_DMA0_CB = 12,
|
||||
CID_DMA1_Y = 13,
|
||||
CID_DMA1_CR = 14,
|
||||
CID_DMA1_CB = 15,
|
||||
CID_RGB0 = 16,
|
||||
CID_RGB1 = 17,
|
||||
CID_RGB2 = 18,
|
||||
CID_VIG3_Y = 19,
|
||||
CID_VIG3_CR = 20,
|
||||
CID_VIG3_CB = 21,
|
||||
CID_RGB3 = 22,
|
||||
CID_MAX = 23,
|
||||
};
|
||||
|
||||
enum mdp5_cursor_format {
|
||||
CURSOR_FMT_ARGB8888 = 0,
|
||||
CURSOR_FMT_ARGB1555 = 2,
|
||||
|
@ -144,30 +120,25 @@ enum mdp5_data_format {
|
|||
DATA_FORMAT_YUV = 1,
|
||||
};
|
||||
|
||||
#define MDP5_IRQ_INTF0_WB_ROT_COMP 0x00000001
|
||||
#define MDP5_IRQ_INTF1_WB_ROT_COMP 0x00000002
|
||||
#define MDP5_IRQ_INTF2_WB_ROT_COMP 0x00000004
|
||||
#define MDP5_IRQ_INTF3_WB_ROT_COMP 0x00000008
|
||||
#define MDP5_IRQ_INTF0_WB_WFD 0x00000010
|
||||
#define MDP5_IRQ_INTF1_WB_WFD 0x00000020
|
||||
#define MDP5_IRQ_INTF2_WB_WFD 0x00000040
|
||||
#define MDP5_IRQ_INTF3_WB_WFD 0x00000080
|
||||
#define MDP5_IRQ_INTF0_PING_PONG_COMP 0x00000100
|
||||
#define MDP5_IRQ_INTF1_PING_PONG_COMP 0x00000200
|
||||
#define MDP5_IRQ_INTF2_PING_PONG_COMP 0x00000400
|
||||
#define MDP5_IRQ_INTF3_PING_PONG_COMP 0x00000800
|
||||
#define MDP5_IRQ_INTF0_PING_PONG_RD_PTR 0x00001000
|
||||
#define MDP5_IRQ_INTF1_PING_PONG_RD_PTR 0x00002000
|
||||
#define MDP5_IRQ_INTF2_PING_PONG_RD_PTR 0x00004000
|
||||
#define MDP5_IRQ_INTF3_PING_PONG_RD_PTR 0x00008000
|
||||
#define MDP5_IRQ_INTF0_PING_PONG_WR_PTR 0x00010000
|
||||
#define MDP5_IRQ_INTF1_PING_PONG_WR_PTR 0x00020000
|
||||
#define MDP5_IRQ_INTF2_PING_PONG_WR_PTR 0x00040000
|
||||
#define MDP5_IRQ_INTF3_PING_PONG_WR_PTR 0x00080000
|
||||
#define MDP5_IRQ_INTF0_PING_PONG_AUTO_REF 0x00100000
|
||||
#define MDP5_IRQ_INTF1_PING_PONG_AUTO_REF 0x00200000
|
||||
#define MDP5_IRQ_INTF2_PING_PONG_AUTO_REF 0x00400000
|
||||
#define MDP5_IRQ_INTF3_PING_PONG_AUTO_REF 0x00800000
|
||||
#define MDP5_IRQ_WB_0_DONE 0x00000001
|
||||
#define MDP5_IRQ_WB_1_DONE 0x00000002
|
||||
#define MDP5_IRQ_WB_2_DONE 0x00000010
|
||||
#define MDP5_IRQ_PING_PONG_0_DONE 0x00000100
|
||||
#define MDP5_IRQ_PING_PONG_1_DONE 0x00000200
|
||||
#define MDP5_IRQ_PING_PONG_2_DONE 0x00000400
|
||||
#define MDP5_IRQ_PING_PONG_3_DONE 0x00000800
|
||||
#define MDP5_IRQ_PING_PONG_0_RD_PTR 0x00001000
|
||||
#define MDP5_IRQ_PING_PONG_1_RD_PTR 0x00002000
|
||||
#define MDP5_IRQ_PING_PONG_2_RD_PTR 0x00004000
|
||||
#define MDP5_IRQ_PING_PONG_3_RD_PTR 0x00008000
|
||||
#define MDP5_IRQ_PING_PONG_0_WR_PTR 0x00010000
|
||||
#define MDP5_IRQ_PING_PONG_1_WR_PTR 0x00020000
|
||||
#define MDP5_IRQ_PING_PONG_2_WR_PTR 0x00040000
|
||||
#define MDP5_IRQ_PING_PONG_3_WR_PTR 0x00080000
|
||||
#define MDP5_IRQ_PING_PONG_0_AUTO_REF 0x00100000
|
||||
#define MDP5_IRQ_PING_PONG_1_AUTO_REF 0x00200000
|
||||
#define MDP5_IRQ_PING_PONG_2_AUTO_REF 0x00400000
|
||||
#define MDP5_IRQ_PING_PONG_3_AUTO_REF 0x00800000
|
||||
#define MDP5_IRQ_INTF0_UNDER_RUN 0x01000000
|
||||
#define MDP5_IRQ_INTF0_VSYNC 0x02000000
|
||||
#define MDP5_IRQ_INTF1_UNDER_RUN 0x04000000
|
||||
|
@ -176,136 +147,186 @@ enum mdp5_data_format {
|
|||
#define MDP5_IRQ_INTF2_VSYNC 0x20000000
|
||||
#define MDP5_IRQ_INTF3_UNDER_RUN 0x40000000
|
||||
#define MDP5_IRQ_INTF3_VSYNC 0x80000000
|
||||
#define REG_MDP5_HW_VERSION 0x00000000
|
||||
|
||||
#define REG_MDP5_HW_INTR_STATUS 0x00000010
|
||||
#define MDP5_HW_INTR_STATUS_INTR_MDP 0x00000001
|
||||
#define MDP5_HW_INTR_STATUS_INTR_DSI0 0x00000010
|
||||
#define MDP5_HW_INTR_STATUS_INTR_DSI1 0x00000020
|
||||
#define MDP5_HW_INTR_STATUS_INTR_HDMI 0x00000100
|
||||
#define MDP5_HW_INTR_STATUS_INTR_EDP 0x00001000
|
||||
|
||||
#define REG_MDP5_MDP_VERSION 0x00000100
|
||||
#define MDP5_MDP_VERSION_MINOR__MASK 0x00ff0000
|
||||
#define MDP5_MDP_VERSION_MINOR__SHIFT 16
|
||||
static inline uint32_t MDP5_MDP_VERSION_MINOR(uint32_t val)
|
||||
#define REG_MDSS_HW_VERSION 0x00000000
|
||||
#define MDSS_HW_VERSION_STEP__MASK 0x0000ffff
|
||||
#define MDSS_HW_VERSION_STEP__SHIFT 0
|
||||
static inline uint32_t MDSS_HW_VERSION_STEP(uint32_t val)
|
||||
{
|
||||
return ((val) << MDP5_MDP_VERSION_MINOR__SHIFT) & MDP5_MDP_VERSION_MINOR__MASK;
|
||||
return ((val) << MDSS_HW_VERSION_STEP__SHIFT) & MDSS_HW_VERSION_STEP__MASK;
|
||||
}
|
||||
#define MDP5_MDP_VERSION_MAJOR__MASK 0xf0000000
|
||||
#define MDP5_MDP_VERSION_MAJOR__SHIFT 28
|
||||
static inline uint32_t MDP5_MDP_VERSION_MAJOR(uint32_t val)
|
||||
#define MDSS_HW_VERSION_MINOR__MASK 0x0fff0000
|
||||
#define MDSS_HW_VERSION_MINOR__SHIFT 16
|
||||
static inline uint32_t MDSS_HW_VERSION_MINOR(uint32_t val)
|
||||
{
|
||||
return ((val) << MDP5_MDP_VERSION_MAJOR__SHIFT) & MDP5_MDP_VERSION_MAJOR__MASK;
|
||||
return ((val) << MDSS_HW_VERSION_MINOR__SHIFT) & MDSS_HW_VERSION_MINOR__MASK;
|
||||
}
|
||||
#define MDSS_HW_VERSION_MAJOR__MASK 0xf0000000
|
||||
#define MDSS_HW_VERSION_MAJOR__SHIFT 28
|
||||
static inline uint32_t MDSS_HW_VERSION_MAJOR(uint32_t val)
|
||||
{
|
||||
return ((val) << MDSS_HW_VERSION_MAJOR__SHIFT) & MDSS_HW_VERSION_MAJOR__MASK;
|
||||
}
|
||||
|
||||
#define REG_MDP5_DISP_INTF_SEL 0x00000104
|
||||
#define MDP5_DISP_INTF_SEL_INTF0__MASK 0x000000ff
|
||||
#define MDP5_DISP_INTF_SEL_INTF0__SHIFT 0
|
||||
static inline uint32_t MDP5_DISP_INTF_SEL_INTF0(enum mdp5_intf val)
|
||||
#define REG_MDSS_HW_INTR_STATUS 0x00000010
|
||||
#define MDSS_HW_INTR_STATUS_INTR_MDP 0x00000001
|
||||
#define MDSS_HW_INTR_STATUS_INTR_DSI0 0x00000010
|
||||
#define MDSS_HW_INTR_STATUS_INTR_DSI1 0x00000020
|
||||
#define MDSS_HW_INTR_STATUS_INTR_HDMI 0x00000100
|
||||
#define MDSS_HW_INTR_STATUS_INTR_EDP 0x00001000
|
||||
|
||||
static inline uint32_t __offset_MDP(uint32_t idx)
|
||||
{
|
||||
return ((val) << MDP5_DISP_INTF_SEL_INTF0__SHIFT) & MDP5_DISP_INTF_SEL_INTF0__MASK;
|
||||
switch (idx) {
|
||||
case 0: return (mdp5_cfg->mdp.base[0]);
|
||||
default: return INVALID_IDX(idx);
|
||||
}
|
||||
}
|
||||
#define MDP5_DISP_INTF_SEL_INTF1__MASK 0x0000ff00
|
||||
#define MDP5_DISP_INTF_SEL_INTF1__SHIFT 8
|
||||
static inline uint32_t MDP5_DISP_INTF_SEL_INTF1(enum mdp5_intf val)
|
||||
static inline uint32_t REG_MDP5_MDP(uint32_t i0) { return 0x00000000 + __offset_MDP(i0); }
|
||||
|
||||
static inline uint32_t REG_MDP5_MDP_HW_VERSION(uint32_t i0) { return 0x00000000 + __offset_MDP(i0); }
|
||||
#define MDP5_MDP_HW_VERSION_STEP__MASK 0x0000ffff
|
||||
#define MDP5_MDP_HW_VERSION_STEP__SHIFT 0
|
||||
static inline uint32_t MDP5_MDP_HW_VERSION_STEP(uint32_t val)
|
||||
{
|
||||
return ((val) << MDP5_DISP_INTF_SEL_INTF1__SHIFT) & MDP5_DISP_INTF_SEL_INTF1__MASK;
|
||||
return ((val) << MDP5_MDP_HW_VERSION_STEP__SHIFT) & MDP5_MDP_HW_VERSION_STEP__MASK;
|
||||
}
|
||||
#define MDP5_DISP_INTF_SEL_INTF2__MASK 0x00ff0000
|
||||
#define MDP5_DISP_INTF_SEL_INTF2__SHIFT 16
|
||||
static inline uint32_t MDP5_DISP_INTF_SEL_INTF2(enum mdp5_intf val)
|
||||
#define MDP5_MDP_HW_VERSION_MINOR__MASK 0x0fff0000
|
||||
#define MDP5_MDP_HW_VERSION_MINOR__SHIFT 16
|
||||
static inline uint32_t MDP5_MDP_HW_VERSION_MINOR(uint32_t val)
|
||||
{
|
||||
return ((val) << MDP5_DISP_INTF_SEL_INTF2__SHIFT) & MDP5_DISP_INTF_SEL_INTF2__MASK;
|
||||
return ((val) << MDP5_MDP_HW_VERSION_MINOR__SHIFT) & MDP5_MDP_HW_VERSION_MINOR__MASK;
|
||||
}
|
||||
#define MDP5_DISP_INTF_SEL_INTF3__MASK 0xff000000
|
||||
#define MDP5_DISP_INTF_SEL_INTF3__SHIFT 24
|
||||
static inline uint32_t MDP5_DISP_INTF_SEL_INTF3(enum mdp5_intf val)
|
||||
#define MDP5_MDP_HW_VERSION_MAJOR__MASK 0xf0000000
|
||||
#define MDP5_MDP_HW_VERSION_MAJOR__SHIFT 28
|
||||
static inline uint32_t MDP5_MDP_HW_VERSION_MAJOR(uint32_t val)
|
||||
{
|
||||
return ((val) << MDP5_DISP_INTF_SEL_INTF3__SHIFT) & MDP5_DISP_INTF_SEL_INTF3__MASK;
|
||||
return ((val) << MDP5_MDP_HW_VERSION_MAJOR__SHIFT) & MDP5_MDP_HW_VERSION_MAJOR__MASK;
|
||||
}
|
||||
|
||||
#define REG_MDP5_INTR_EN 0x00000110
|
||||
|
||||
#define REG_MDP5_INTR_STATUS 0x00000114
|
||||
|
||||
#define REG_MDP5_INTR_CLEAR 0x00000118
|
||||
|
||||
#define REG_MDP5_HIST_INTR_EN 0x0000011c
|
||||
|
||||
#define REG_MDP5_HIST_INTR_STATUS 0x00000120
|
||||
|
||||
#define REG_MDP5_HIST_INTR_CLEAR 0x00000124
|
||||
|
||||
static inline uint32_t REG_MDP5_SMP_ALLOC_W(uint32_t i0) { return 0x00000180 + 0x4*i0; }
|
||||
|
||||
static inline uint32_t REG_MDP5_SMP_ALLOC_W_REG(uint32_t i0) { return 0x00000180 + 0x4*i0; }
|
||||
#define MDP5_SMP_ALLOC_W_REG_CLIENT0__MASK 0x000000ff
|
||||
#define MDP5_SMP_ALLOC_W_REG_CLIENT0__SHIFT 0
|
||||
static inline uint32_t MDP5_SMP_ALLOC_W_REG_CLIENT0(enum mdp5_client_id val)
|
||||
static inline uint32_t REG_MDP5_MDP_DISP_INTF_SEL(uint32_t i0) { return 0x00000004 + __offset_MDP(i0); }
|
||||
#define MDP5_MDP_DISP_INTF_SEL_INTF0__MASK 0x000000ff
|
||||
#define MDP5_MDP_DISP_INTF_SEL_INTF0__SHIFT 0
|
||||
static inline uint32_t MDP5_MDP_DISP_INTF_SEL_INTF0(enum mdp5_intf_type val)
|
||||
{
|
||||
return ((val) << MDP5_SMP_ALLOC_W_REG_CLIENT0__SHIFT) & MDP5_SMP_ALLOC_W_REG_CLIENT0__MASK;
|
||||
return ((val) << MDP5_MDP_DISP_INTF_SEL_INTF0__SHIFT) & MDP5_MDP_DISP_INTF_SEL_INTF0__MASK;
|
||||
}
|
||||
#define MDP5_SMP_ALLOC_W_REG_CLIENT1__MASK 0x0000ff00
|
||||
#define MDP5_SMP_ALLOC_W_REG_CLIENT1__SHIFT 8
|
||||
static inline uint32_t MDP5_SMP_ALLOC_W_REG_CLIENT1(enum mdp5_client_id val)
|
||||
#define MDP5_MDP_DISP_INTF_SEL_INTF1__MASK 0x0000ff00
|
||||
#define MDP5_MDP_DISP_INTF_SEL_INTF1__SHIFT 8
|
||||
static inline uint32_t MDP5_MDP_DISP_INTF_SEL_INTF1(enum mdp5_intf_type val)
|
||||
{
|
||||
return ((val) << MDP5_SMP_ALLOC_W_REG_CLIENT1__SHIFT) & MDP5_SMP_ALLOC_W_REG_CLIENT1__MASK;
|
||||
return ((val) << MDP5_MDP_DISP_INTF_SEL_INTF1__SHIFT) & MDP5_MDP_DISP_INTF_SEL_INTF1__MASK;
|
||||
}
|
||||
#define MDP5_SMP_ALLOC_W_REG_CLIENT2__MASK 0x00ff0000
|
||||
#define MDP5_SMP_ALLOC_W_REG_CLIENT2__SHIFT 16
|
||||
static inline uint32_t MDP5_SMP_ALLOC_W_REG_CLIENT2(enum mdp5_client_id val)
|
||||
#define MDP5_MDP_DISP_INTF_SEL_INTF2__MASK 0x00ff0000
|
||||
#define MDP5_MDP_DISP_INTF_SEL_INTF2__SHIFT 16
|
||||
static inline uint32_t MDP5_MDP_DISP_INTF_SEL_INTF2(enum mdp5_intf_type val)
|
||||
{
|
||||
return ((val) << MDP5_SMP_ALLOC_W_REG_CLIENT2__SHIFT) & MDP5_SMP_ALLOC_W_REG_CLIENT2__MASK;
|
||||
return ((val) << MDP5_MDP_DISP_INTF_SEL_INTF2__SHIFT) & MDP5_MDP_DISP_INTF_SEL_INTF2__MASK;
|
||||
}
|
||||
#define MDP5_MDP_DISP_INTF_SEL_INTF3__MASK 0xff000000
|
||||
#define MDP5_MDP_DISP_INTF_SEL_INTF3__SHIFT 24
|
||||
static inline uint32_t MDP5_MDP_DISP_INTF_SEL_INTF3(enum mdp5_intf_type val)
|
||||
{
|
||||
return ((val) << MDP5_MDP_DISP_INTF_SEL_INTF3__SHIFT) & MDP5_MDP_DISP_INTF_SEL_INTF3__MASK;
|
||||
}
|
||||
|
||||
static inline uint32_t REG_MDP5_SMP_ALLOC_R(uint32_t i0) { return 0x00000230 + 0x4*i0; }
|
||||
static inline uint32_t REG_MDP5_MDP_INTR_EN(uint32_t i0) { return 0x00000010 + __offset_MDP(i0); }
|
||||
|
||||
static inline uint32_t REG_MDP5_SMP_ALLOC_R_REG(uint32_t i0) { return 0x00000230 + 0x4*i0; }
|
||||
#define MDP5_SMP_ALLOC_R_REG_CLIENT0__MASK 0x000000ff
|
||||
#define MDP5_SMP_ALLOC_R_REG_CLIENT0__SHIFT 0
|
||||
static inline uint32_t MDP5_SMP_ALLOC_R_REG_CLIENT0(enum mdp5_client_id val)
|
||||
static inline uint32_t REG_MDP5_MDP_INTR_STATUS(uint32_t i0) { return 0x00000014 + __offset_MDP(i0); }
|
||||
|
||||
static inline uint32_t REG_MDP5_MDP_INTR_CLEAR(uint32_t i0) { return 0x00000018 + __offset_MDP(i0); }
|
||||
|
||||
static inline uint32_t REG_MDP5_MDP_HIST_INTR_EN(uint32_t i0) { return 0x0000001c + __offset_MDP(i0); }
|
||||
|
||||
static inline uint32_t REG_MDP5_MDP_HIST_INTR_STATUS(uint32_t i0) { return 0x00000020 + __offset_MDP(i0); }
|
||||
|
||||
static inline uint32_t REG_MDP5_MDP_HIST_INTR_CLEAR(uint32_t i0) { return 0x00000024 + __offset_MDP(i0); }
|
||||
|
||||
static inline uint32_t REG_MDP5_MDP_SPARE_0(uint32_t i0) { return 0x00000028 + __offset_MDP(i0); }
|
||||
#define MDP5_MDP_SPARE_0_SPLIT_DPL_SINGLE_FLUSH_EN 0x00000001
|
||||
|
||||
static inline uint32_t REG_MDP5_MDP_SMP_ALLOC_W(uint32_t i0, uint32_t i1) { return 0x00000080 + __offset_MDP(i0) + 0x4*i1; }
|
||||
|
||||
static inline uint32_t REG_MDP5_MDP_SMP_ALLOC_W_REG(uint32_t i0, uint32_t i1) { return 0x00000080 + __offset_MDP(i0) + 0x4*i1; }
|
||||
#define MDP5_MDP_SMP_ALLOC_W_REG_CLIENT0__MASK 0x000000ff
|
||||
#define MDP5_MDP_SMP_ALLOC_W_REG_CLIENT0__SHIFT 0
|
||||
static inline uint32_t MDP5_MDP_SMP_ALLOC_W_REG_CLIENT0(uint32_t val)
|
||||
{
|
||||
return ((val) << MDP5_SMP_ALLOC_R_REG_CLIENT0__SHIFT) & MDP5_SMP_ALLOC_R_REG_CLIENT0__MASK;
|
||||
return ((val) << MDP5_MDP_SMP_ALLOC_W_REG_CLIENT0__SHIFT) & MDP5_MDP_SMP_ALLOC_W_REG_CLIENT0__MASK;
|
||||
}
|
||||
#define MDP5_SMP_ALLOC_R_REG_CLIENT1__MASK 0x0000ff00
|
||||
#define MDP5_SMP_ALLOC_R_REG_CLIENT1__SHIFT 8
|
||||
static inline uint32_t MDP5_SMP_ALLOC_R_REG_CLIENT1(enum mdp5_client_id val)
|
||||
#define MDP5_MDP_SMP_ALLOC_W_REG_CLIENT1__MASK 0x0000ff00
|
||||
#define MDP5_MDP_SMP_ALLOC_W_REG_CLIENT1__SHIFT 8
|
||||
static inline uint32_t MDP5_MDP_SMP_ALLOC_W_REG_CLIENT1(uint32_t val)
|
||||
{
|
||||
return ((val) << MDP5_SMP_ALLOC_R_REG_CLIENT1__SHIFT) & MDP5_SMP_ALLOC_R_REG_CLIENT1__MASK;
|
||||
return ((val) << MDP5_MDP_SMP_ALLOC_W_REG_CLIENT1__SHIFT) & MDP5_MDP_SMP_ALLOC_W_REG_CLIENT1__MASK;
|
||||
}
|
||||
#define MDP5_SMP_ALLOC_R_REG_CLIENT2__MASK 0x00ff0000
|
||||
#define MDP5_SMP_ALLOC_R_REG_CLIENT2__SHIFT 16
|
||||
static inline uint32_t MDP5_SMP_ALLOC_R_REG_CLIENT2(enum mdp5_client_id val)
|
||||
#define MDP5_MDP_SMP_ALLOC_W_REG_CLIENT2__MASK 0x00ff0000
|
||||
#define MDP5_MDP_SMP_ALLOC_W_REG_CLIENT2__SHIFT 16
|
||||
static inline uint32_t MDP5_MDP_SMP_ALLOC_W_REG_CLIENT2(uint32_t val)
|
||||
{
|
||||
return ((val) << MDP5_SMP_ALLOC_R_REG_CLIENT2__SHIFT) & MDP5_SMP_ALLOC_R_REG_CLIENT2__MASK;
|
||||
return ((val) << MDP5_MDP_SMP_ALLOC_W_REG_CLIENT2__SHIFT) & MDP5_MDP_SMP_ALLOC_W_REG_CLIENT2__MASK;
|
||||
}
|
||||
|
||||
static inline uint32_t REG_MDP5_MDP_SMP_ALLOC_R(uint32_t i0, uint32_t i1) { return 0x00000130 + __offset_MDP(i0) + 0x4*i1; }
|
||||
|
||||
static inline uint32_t REG_MDP5_MDP_SMP_ALLOC_R_REG(uint32_t i0, uint32_t i1) { return 0x00000130 + __offset_MDP(i0) + 0x4*i1; }
|
||||
#define MDP5_MDP_SMP_ALLOC_R_REG_CLIENT0__MASK 0x000000ff
|
||||
#define MDP5_MDP_SMP_ALLOC_R_REG_CLIENT0__SHIFT 0
|
||||
static inline uint32_t MDP5_MDP_SMP_ALLOC_R_REG_CLIENT0(uint32_t val)
|
||||
{
|
||||
return ((val) << MDP5_MDP_SMP_ALLOC_R_REG_CLIENT0__SHIFT) & MDP5_MDP_SMP_ALLOC_R_REG_CLIENT0__MASK;
|
||||
}
|
||||
#define MDP5_MDP_SMP_ALLOC_R_REG_CLIENT1__MASK 0x0000ff00
|
||||
#define MDP5_MDP_SMP_ALLOC_R_REG_CLIENT1__SHIFT 8
|
||||
static inline uint32_t MDP5_MDP_SMP_ALLOC_R_REG_CLIENT1(uint32_t val)
|
||||
{
|
||||
return ((val) << MDP5_MDP_SMP_ALLOC_R_REG_CLIENT1__SHIFT) & MDP5_MDP_SMP_ALLOC_R_REG_CLIENT1__MASK;
|
||||
}
|
||||
#define MDP5_MDP_SMP_ALLOC_R_REG_CLIENT2__MASK 0x00ff0000
|
||||
#define MDP5_MDP_SMP_ALLOC_R_REG_CLIENT2__SHIFT 16
|
||||
static inline uint32_t MDP5_MDP_SMP_ALLOC_R_REG_CLIENT2(uint32_t val)
|
||||
{
|
||||
return ((val) << MDP5_MDP_SMP_ALLOC_R_REG_CLIENT2__SHIFT) & MDP5_MDP_SMP_ALLOC_R_REG_CLIENT2__MASK;
|
||||
}
|
||||
|
||||
static inline uint32_t __offset_IGC(enum mdp5_igc_type idx)
|
||||
{
|
||||
switch (idx) {
|
||||
case IGC_VIG: return 0x00000300;
|
||||
case IGC_RGB: return 0x00000310;
|
||||
case IGC_DMA: return 0x00000320;
|
||||
case IGC_DSPP: return 0x00000400;
|
||||
case IGC_VIG: return 0x00000200;
|
||||
case IGC_RGB: return 0x00000210;
|
||||
case IGC_DMA: return 0x00000220;
|
||||
case IGC_DSPP: return 0x00000300;
|
||||
default: return INVALID_IDX(idx);
|
||||
}
|
||||
}
|
||||
static inline uint32_t REG_MDP5_IGC(enum mdp5_igc_type i0) { return 0x00000000 + __offset_IGC(i0); }
|
||||
static inline uint32_t REG_MDP5_MDP_IGC(uint32_t i0, enum mdp5_igc_type i1) { return 0x00000000 + __offset_MDP(i0) + __offset_IGC(i1); }
|
||||
|
||||
static inline uint32_t REG_MDP5_IGC_LUT(enum mdp5_igc_type i0, uint32_t i1) { return 0x00000000 + __offset_IGC(i0) + 0x4*i1; }
|
||||
static inline uint32_t REG_MDP5_MDP_IGC_LUT(uint32_t i0, enum mdp5_igc_type i1, uint32_t i2) { return 0x00000000 + __offset_MDP(i0) + __offset_IGC(i1) + 0x4*i2; }
|
||||
|
||||
static inline uint32_t REG_MDP5_IGC_LUT_REG(enum mdp5_igc_type i0, uint32_t i1) { return 0x00000000 + __offset_IGC(i0) + 0x4*i1; }
|
||||
#define MDP5_IGC_LUT_REG_VAL__MASK 0x00000fff
|
||||
#define MDP5_IGC_LUT_REG_VAL__SHIFT 0
|
||||
static inline uint32_t MDP5_IGC_LUT_REG_VAL(uint32_t val)
|
||||
static inline uint32_t REG_MDP5_MDP_IGC_LUT_REG(uint32_t i0, enum mdp5_igc_type i1, uint32_t i2) { return 0x00000000 + __offset_MDP(i0) + __offset_IGC(i1) + 0x4*i2; }
|
||||
#define MDP5_MDP_IGC_LUT_REG_VAL__MASK 0x00000fff
|
||||
#define MDP5_MDP_IGC_LUT_REG_VAL__SHIFT 0
|
||||
static inline uint32_t MDP5_MDP_IGC_LUT_REG_VAL(uint32_t val)
|
||||
{
|
||||
return ((val) << MDP5_IGC_LUT_REG_VAL__SHIFT) & MDP5_IGC_LUT_REG_VAL__MASK;
|
||||
return ((val) << MDP5_MDP_IGC_LUT_REG_VAL__SHIFT) & MDP5_MDP_IGC_LUT_REG_VAL__MASK;
|
||||
}
|
||||
#define MDP5_IGC_LUT_REG_INDEX_UPDATE 0x02000000
|
||||
#define MDP5_IGC_LUT_REG_DISABLE_PIPE_0 0x10000000
|
||||
#define MDP5_IGC_LUT_REG_DISABLE_PIPE_1 0x20000000
|
||||
#define MDP5_IGC_LUT_REG_DISABLE_PIPE_2 0x40000000
|
||||
#define MDP5_MDP_IGC_LUT_REG_INDEX_UPDATE 0x02000000
|
||||
#define MDP5_MDP_IGC_LUT_REG_DISABLE_PIPE_0 0x10000000
|
||||
#define MDP5_MDP_IGC_LUT_REG_DISABLE_PIPE_1 0x20000000
|
||||
#define MDP5_MDP_IGC_LUT_REG_DISABLE_PIPE_2 0x40000000
|
||||
|
||||
#define REG_MDP5_SPLIT_DPL_EN 0x000003f4
|
||||
|
||||
#define REG_MDP5_SPLIT_DPL_UPPER 0x000003f8
|
||||
#define MDP5_SPLIT_DPL_UPPER_SMART_PANEL 0x00000002
|
||||
#define MDP5_SPLIT_DPL_UPPER_SMART_PANEL_FREE_RUN 0x00000004
|
||||
#define MDP5_SPLIT_DPL_UPPER_INTF1_SW_TRG_MUX 0x00000010
|
||||
#define MDP5_SPLIT_DPL_UPPER_INTF2_SW_TRG_MUX 0x00000100
|
||||
|
||||
#define REG_MDP5_SPLIT_DPL_LOWER 0x000004f0
|
||||
#define MDP5_SPLIT_DPL_LOWER_SMART_PANEL 0x00000002
|
||||
#define MDP5_SPLIT_DPL_LOWER_SMART_PANEL_FREE_RUN 0x00000004
|
||||
#define MDP5_SPLIT_DPL_LOWER_INTF1_TG_SYNC 0x00000010
|
||||
#define MDP5_SPLIT_DPL_LOWER_INTF2_TG_SYNC 0x00000100
|
||||
|
||||
static inline uint32_t __offset_CTL(uint32_t idx)
|
||||
{
|
||||
|
@ -437,11 +458,19 @@ static inline uint32_t REG_MDP5_CTL_FLUSH(uint32_t i0) { return 0x00000018 + __o
|
|||
#define MDP5_CTL_FLUSH_DSPP0 0x00002000
|
||||
#define MDP5_CTL_FLUSH_DSPP1 0x00004000
|
||||
#define MDP5_CTL_FLUSH_DSPP2 0x00008000
|
||||
#define MDP5_CTL_FLUSH_WB 0x00010000
|
||||
#define MDP5_CTL_FLUSH_CTL 0x00020000
|
||||
#define MDP5_CTL_FLUSH_VIG3 0x00040000
|
||||
#define MDP5_CTL_FLUSH_RGB3 0x00080000
|
||||
#define MDP5_CTL_FLUSH_LM5 0x00100000
|
||||
#define MDP5_CTL_FLUSH_DSPP3 0x00200000
|
||||
#define MDP5_CTL_FLUSH_CURSOR_0 0x00400000
|
||||
#define MDP5_CTL_FLUSH_CURSOR_1 0x00800000
|
||||
#define MDP5_CTL_FLUSH_CHROMADOWN_0 0x04000000
|
||||
#define MDP5_CTL_FLUSH_TIMING_3 0x10000000
|
||||
#define MDP5_CTL_FLUSH_TIMING_2 0x20000000
|
||||
#define MDP5_CTL_FLUSH_TIMING_1 0x40000000
|
||||
#define MDP5_CTL_FLUSH_TIMING_0 0x80000000
|
||||
|
||||
static inline uint32_t REG_MDP5_CTL_START(uint32_t i0) { return 0x0000001c + __offset_CTL(i0); }
|
||||
|
||||
|
@ -1117,6 +1146,94 @@ static inline uint32_t REG_MDP5_DSPP_GAMUT_BASE(uint32_t i0) { return 0x000002dc
|
|||
|
||||
static inline uint32_t REG_MDP5_DSPP_GC_BASE(uint32_t i0) { return 0x000002b0 + __offset_DSPP(i0); }
|
||||
|
||||
static inline uint32_t __offset_PP(uint32_t idx)
|
||||
{
|
||||
switch (idx) {
|
||||
case 0: return (mdp5_cfg->pp.base[0]);
|
||||
case 1: return (mdp5_cfg->pp.base[1]);
|
||||
case 2: return (mdp5_cfg->pp.base[2]);
|
||||
case 3: return (mdp5_cfg->pp.base[3]);
|
||||
default: return INVALID_IDX(idx);
|
||||
}
|
||||
}
|
||||
static inline uint32_t REG_MDP5_PP(uint32_t i0) { return 0x00000000 + __offset_PP(i0); }
|
||||
|
||||
static inline uint32_t REG_MDP5_PP_TEAR_CHECK_EN(uint32_t i0) { return 0x00000000 + __offset_PP(i0); }
|
||||
|
||||
static inline uint32_t REG_MDP5_PP_SYNC_CONFIG_VSYNC(uint32_t i0) { return 0x00000004 + __offset_PP(i0); }
|
||||
#define MDP5_PP_SYNC_CONFIG_VSYNC_COUNT__MASK 0x0007ffff
|
||||
#define MDP5_PP_SYNC_CONFIG_VSYNC_COUNT__SHIFT 0
|
||||
static inline uint32_t MDP5_PP_SYNC_CONFIG_VSYNC_COUNT(uint32_t val)
|
||||
{
|
||||
return ((val) << MDP5_PP_SYNC_CONFIG_VSYNC_COUNT__SHIFT) & MDP5_PP_SYNC_CONFIG_VSYNC_COUNT__MASK;
|
||||
}
|
||||
#define MDP5_PP_SYNC_CONFIG_VSYNC_COUNTER_EN 0x00080000
|
||||
#define MDP5_PP_SYNC_CONFIG_VSYNC_IN_EN 0x00100000
|
||||
|
||||
static inline uint32_t REG_MDP5_PP_SYNC_CONFIG_HEIGHT(uint32_t i0) { return 0x00000008 + __offset_PP(i0); }
|
||||
|
||||
static inline uint32_t REG_MDP5_PP_SYNC_WRCOUNT(uint32_t i0) { return 0x0000000c + __offset_PP(i0); }
|
||||
#define MDP5_PP_SYNC_WRCOUNT_LINE_COUNT__MASK 0x0000ffff
|
||||
#define MDP5_PP_SYNC_WRCOUNT_LINE_COUNT__SHIFT 0
|
||||
static inline uint32_t MDP5_PP_SYNC_WRCOUNT_LINE_COUNT(uint32_t val)
|
||||
{
|
||||
return ((val) << MDP5_PP_SYNC_WRCOUNT_LINE_COUNT__SHIFT) & MDP5_PP_SYNC_WRCOUNT_LINE_COUNT__MASK;
|
||||
}
|
||||
#define MDP5_PP_SYNC_WRCOUNT_FRAME_COUNT__MASK 0xffff0000
|
||||
#define MDP5_PP_SYNC_WRCOUNT_FRAME_COUNT__SHIFT 16
|
||||
static inline uint32_t MDP5_PP_SYNC_WRCOUNT_FRAME_COUNT(uint32_t val)
|
||||
{
|
||||
return ((val) << MDP5_PP_SYNC_WRCOUNT_FRAME_COUNT__SHIFT) & MDP5_PP_SYNC_WRCOUNT_FRAME_COUNT__MASK;
|
||||
}
|
||||
|
||||
static inline uint32_t REG_MDP5_PP_VSYNC_INIT_VAL(uint32_t i0) { return 0x00000010 + __offset_PP(i0); }
|
||||
|
||||
static inline uint32_t REG_MDP5_PP_INT_COUNT_VAL(uint32_t i0) { return 0x00000014 + __offset_PP(i0); }
|
||||
#define MDP5_PP_INT_COUNT_VAL_LINE_COUNT__MASK 0x0000ffff
|
||||
#define MDP5_PP_INT_COUNT_VAL_LINE_COUNT__SHIFT 0
|
||||
static inline uint32_t MDP5_PP_INT_COUNT_VAL_LINE_COUNT(uint32_t val)
|
||||
{
|
||||
return ((val) << MDP5_PP_INT_COUNT_VAL_LINE_COUNT__SHIFT) & MDP5_PP_INT_COUNT_VAL_LINE_COUNT__MASK;
|
||||
}
|
||||
#define MDP5_PP_INT_COUNT_VAL_FRAME_COUNT__MASK 0xffff0000
|
||||
#define MDP5_PP_INT_COUNT_VAL_FRAME_COUNT__SHIFT 16
|
||||
static inline uint32_t MDP5_PP_INT_COUNT_VAL_FRAME_COUNT(uint32_t val)
|
||||
{
|
||||
return ((val) << MDP5_PP_INT_COUNT_VAL_FRAME_COUNT__SHIFT) & MDP5_PP_INT_COUNT_VAL_FRAME_COUNT__MASK;
|
||||
}
|
||||
|
||||
static inline uint32_t REG_MDP5_PP_SYNC_THRESH(uint32_t i0) { return 0x00000018 + __offset_PP(i0); }
|
||||
#define MDP5_PP_SYNC_THRESH_START__MASK 0x0000ffff
|
||||
#define MDP5_PP_SYNC_THRESH_START__SHIFT 0
|
||||
static inline uint32_t MDP5_PP_SYNC_THRESH_START(uint32_t val)
|
||||
{
|
||||
return ((val) << MDP5_PP_SYNC_THRESH_START__SHIFT) & MDP5_PP_SYNC_THRESH_START__MASK;
|
||||
}
|
||||
#define MDP5_PP_SYNC_THRESH_CONTINUE__MASK 0xffff0000
|
||||
#define MDP5_PP_SYNC_THRESH_CONTINUE__SHIFT 16
|
||||
static inline uint32_t MDP5_PP_SYNC_THRESH_CONTINUE(uint32_t val)
|
||||
{
|
||||
return ((val) << MDP5_PP_SYNC_THRESH_CONTINUE__SHIFT) & MDP5_PP_SYNC_THRESH_CONTINUE__MASK;
|
||||
}
|
||||
|
||||
static inline uint32_t REG_MDP5_PP_START_POS(uint32_t i0) { return 0x0000001c + __offset_PP(i0); }
|
||||
|
||||
static inline uint32_t REG_MDP5_PP_RD_PTR_IRQ(uint32_t i0) { return 0x00000020 + __offset_PP(i0); }
|
||||
|
||||
static inline uint32_t REG_MDP5_PP_WR_PTR_IRQ(uint32_t i0) { return 0x00000024 + __offset_PP(i0); }
|
||||
|
||||
static inline uint32_t REG_MDP5_PP_OUT_LINE_COUNT(uint32_t i0) { return 0x00000028 + __offset_PP(i0); }
|
||||
|
||||
static inline uint32_t REG_MDP5_PP_PP_LINE_COUNT(uint32_t i0) { return 0x0000002c + __offset_PP(i0); }
|
||||
|
||||
static inline uint32_t REG_MDP5_PP_AUTOREFRESH_CONFIG(uint32_t i0) { return 0x00000030 + __offset_PP(i0); }
|
||||
|
||||
static inline uint32_t REG_MDP5_PP_FBC_MODE(uint32_t i0) { return 0x00000034 + __offset_PP(i0); }
|
||||
|
||||
static inline uint32_t REG_MDP5_PP_FBC_BUDGET_CTL(uint32_t i0) { return 0x00000038 + __offset_PP(i0); }
|
||||
|
||||
static inline uint32_t REG_MDP5_PP_FBC_LOSSY_MODE(uint32_t i0) { return 0x0000003c + __offset_PP(i0); }
|
||||
|
||||
static inline uint32_t __offset_INTF(uint32_t idx)
|
||||
{
|
||||
switch (idx) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2014 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2014-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
|
||||
|
@ -24,13 +24,23 @@ const struct mdp5_cfg_hw *mdp5_cfg = NULL;
|
|||
|
||||
const struct mdp5_cfg_hw msm8x74_config = {
|
||||
.name = "msm8x74",
|
||||
.mdp = {
|
||||
.count = 1,
|
||||
.base = { 0x00100 },
|
||||
},
|
||||
.smp = {
|
||||
.mmb_count = 22,
|
||||
.mmb_size = 4096,
|
||||
.clients = {
|
||||
[SSPP_VIG0] = 1, [SSPP_VIG1] = 4, [SSPP_VIG2] = 7,
|
||||
[SSPP_DMA0] = 10, [SSPP_DMA1] = 13,
|
||||
[SSPP_RGB0] = 16, [SSPP_RGB1] = 17, [SSPP_RGB2] = 18,
|
||||
},
|
||||
},
|
||||
.ctl = {
|
||||
.count = 5,
|
||||
.base = { 0x00600, 0x00700, 0x00800, 0x00900, 0x00a00 },
|
||||
.flush_hw_mask = 0x0003ffff,
|
||||
},
|
||||
.pipe_vig = {
|
||||
.count = 3,
|
||||
|
@ -57,27 +67,49 @@ const struct mdp5_cfg_hw msm8x74_config = {
|
|||
.count = 2,
|
||||
.base = { 0x13100, 0x13300 }, /* NOTE: no ad in v1.0 */
|
||||
},
|
||||
.pp = {
|
||||
.count = 3,
|
||||
.base = { 0x12d00, 0x12e00, 0x12f00 },
|
||||
},
|
||||
.intf = {
|
||||
.count = 4,
|
||||
.base = { 0x12500, 0x12700, 0x12900, 0x12b00 },
|
||||
},
|
||||
.intfs = {
|
||||
[0] = INTF_eDP,
|
||||
[1] = INTF_DSI,
|
||||
[2] = INTF_DSI,
|
||||
[3] = INTF_HDMI,
|
||||
},
|
||||
.max_clk = 200000000,
|
||||
};
|
||||
|
||||
const struct mdp5_cfg_hw apq8084_config = {
|
||||
.name = "apq8084",
|
||||
.mdp = {
|
||||
.count = 1,
|
||||
.base = { 0x00100 },
|
||||
},
|
||||
.smp = {
|
||||
.mmb_count = 44,
|
||||
.mmb_size = 8192,
|
||||
.clients = {
|
||||
[SSPP_VIG0] = 1, [SSPP_VIG1] = 4,
|
||||
[SSPP_VIG2] = 7, [SSPP_VIG3] = 19,
|
||||
[SSPP_DMA0] = 10, [SSPP_DMA1] = 13,
|
||||
[SSPP_RGB0] = 16, [SSPP_RGB1] = 17,
|
||||
[SSPP_RGB2] = 18, [SSPP_RGB3] = 22,
|
||||
},
|
||||
.reserved_state[0] = GENMASK(7, 0), /* first 8 MMBs */
|
||||
.reserved[CID_RGB0] = 2,
|
||||
.reserved[CID_RGB1] = 2,
|
||||
.reserved[CID_RGB2] = 2,
|
||||
.reserved[CID_RGB3] = 2,
|
||||
.reserved = {
|
||||
/* Two SMP blocks are statically tied to RGB pipes: */
|
||||
[16] = 2, [17] = 2, [18] = 2, [22] = 2,
|
||||
},
|
||||
},
|
||||
.ctl = {
|
||||
.count = 5,
|
||||
.base = { 0x00600, 0x00700, 0x00800, 0x00900, 0x00a00 },
|
||||
.flush_hw_mask = 0x003fffff,
|
||||
},
|
||||
.pipe_vig = {
|
||||
.count = 4,
|
||||
|
@ -105,10 +137,69 @@ const struct mdp5_cfg_hw apq8084_config = {
|
|||
.count = 3,
|
||||
.base = { 0x13500, 0x13700, 0x13900 },
|
||||
},
|
||||
.pp = {
|
||||
.count = 4,
|
||||
.base = { 0x12f00, 0x13000, 0x13100, 0x13200 },
|
||||
},
|
||||
.intf = {
|
||||
.count = 5,
|
||||
.base = { 0x12500, 0x12700, 0x12900, 0x12b00, 0x12d00 },
|
||||
},
|
||||
.intfs = {
|
||||
[0] = INTF_eDP,
|
||||
[1] = INTF_DSI,
|
||||
[2] = INTF_DSI,
|
||||
[3] = INTF_HDMI,
|
||||
},
|
||||
.max_clk = 320000000,
|
||||
};
|
||||
|
||||
const struct mdp5_cfg_hw msm8x16_config = {
|
||||
.name = "msm8x16",
|
||||
.mdp = {
|
||||
.count = 1,
|
||||
.base = { 0x01000 },
|
||||
},
|
||||
.smp = {
|
||||
.mmb_count = 8,
|
||||
.mmb_size = 8192,
|
||||
.clients = {
|
||||
[SSPP_VIG0] = 1, [SSPP_DMA0] = 4,
|
||||
[SSPP_RGB0] = 7, [SSPP_RGB1] = 8,
|
||||
},
|
||||
},
|
||||
.ctl = {
|
||||
.count = 5,
|
||||
.base = { 0x02000, 0x02200, 0x02400, 0x02600, 0x02800 },
|
||||
.flush_hw_mask = 0x4003ffff,
|
||||
},
|
||||
.pipe_vig = {
|
||||
.count = 1,
|
||||
.base = { 0x05000 },
|
||||
},
|
||||
.pipe_rgb = {
|
||||
.count = 2,
|
||||
.base = { 0x15000, 0x17000 },
|
||||
},
|
||||
.pipe_dma = {
|
||||
.count = 1,
|
||||
.base = { 0x25000 },
|
||||
},
|
||||
.lm = {
|
||||
.count = 2, /* LM0 and LM3 */
|
||||
.base = { 0x45000, 0x48000 },
|
||||
.nb_stages = 5,
|
||||
},
|
||||
.dspp = {
|
||||
.count = 1,
|
||||
.base = { 0x55000 },
|
||||
|
||||
},
|
||||
.intf = {
|
||||
.count = 1, /* INTF_1 */
|
||||
.base = { 0x6B800 },
|
||||
},
|
||||
/* TODO enable .intfs[] with [1] = INTF_DSI, once DSI is implemented */
|
||||
.max_clk = 320000000,
|
||||
};
|
||||
|
||||
|
@ -116,6 +207,7 @@ static const struct mdp5_cfg_handler cfg_handlers[] = {
|
|||
{ .revision = 0, .config = { .hw = &msm8x74_config } },
|
||||
{ .revision = 2, .config = { .hw = &msm8x74_config } },
|
||||
{ .revision = 3, .config = { .hw = &apq8084_config } },
|
||||
{ .revision = 6, .config = { .hw = &msm8x16_config } },
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -44,26 +44,38 @@ struct mdp5_lm_block {
|
|||
uint32_t nb_stages; /* number of stages per blender */
|
||||
};
|
||||
|
||||
struct mdp5_ctl_block {
|
||||
MDP5_SUB_BLOCK_DEFINITION;
|
||||
uint32_t flush_hw_mask; /* FLUSH register's hardware mask */
|
||||
};
|
||||
|
||||
struct mdp5_smp_block {
|
||||
int mmb_count; /* number of SMP MMBs */
|
||||
int mmb_size; /* MMB: size in bytes */
|
||||
uint32_t clients[MAX_CLIENTS]; /* SMP port allocation /pipe */
|
||||
mdp5_smp_state_t reserved_state;/* SMP MMBs statically allocated */
|
||||
int reserved[MAX_CLIENTS]; /* # of MMBs allocated per client */
|
||||
};
|
||||
|
||||
#define MDP5_INTF_NUM_MAX 5
|
||||
|
||||
struct mdp5_cfg_hw {
|
||||
char *name;
|
||||
|
||||
struct mdp5_sub_block mdp;
|
||||
struct mdp5_smp_block smp;
|
||||
struct mdp5_sub_block ctl;
|
||||
struct mdp5_ctl_block ctl;
|
||||
struct mdp5_sub_block pipe_vig;
|
||||
struct mdp5_sub_block pipe_rgb;
|
||||
struct mdp5_sub_block pipe_dma;
|
||||
struct mdp5_lm_block lm;
|
||||
struct mdp5_sub_block dspp;
|
||||
struct mdp5_sub_block ad;
|
||||
struct mdp5_sub_block pp;
|
||||
struct mdp5_sub_block intf;
|
||||
|
||||
u32 intfs[MDP5_INTF_NUM_MAX]; /* array of enum mdp5_intf_type */
|
||||
|
||||
uint32_t max_clk;
|
||||
};
|
||||
|
||||
|
@ -84,6 +96,10 @@ const struct mdp5_cfg_hw *mdp5_cfg_get_hw_config(struct mdp5_cfg_handler *cfg_hn
|
|||
struct mdp5_cfg *mdp5_cfg_get_config(struct mdp5_cfg_handler *cfg_hnd);
|
||||
int mdp5_cfg_get_hw_rev(struct mdp5_cfg_handler *cfg_hnd);
|
||||
|
||||
#define mdp5_cfg_intf_is_virtual(intf_type) ({ \
|
||||
typeof(intf_type) __val = (intf_type); \
|
||||
(__val) >= INTF_VIRTUAL ? true : false; })
|
||||
|
||||
struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms,
|
||||
uint32_t major, uint32_t minor);
|
||||
void mdp5_cfg_destroy(struct mdp5_cfg_handler *cfg_hnd);
|
||||
|
|
|
@ -0,0 +1,343 @@
|
|||
/*
|
||||
* 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 "mdp5_kms.h"
|
||||
|
||||
#include "drm_crtc.h"
|
||||
#include "drm_crtc_helper.h"
|
||||
|
||||
struct mdp5_cmd_encoder {
|
||||
struct drm_encoder base;
|
||||
struct mdp5_interface intf;
|
||||
bool enabled;
|
||||
uint32_t bsc;
|
||||
};
|
||||
#define to_mdp5_cmd_encoder(x) container_of(x, struct mdp5_cmd_encoder, base)
|
||||
|
||||
static struct mdp5_kms *get_kms(struct drm_encoder *encoder)
|
||||
{
|
||||
struct msm_drm_private *priv = encoder->dev->dev_private;
|
||||
return to_mdp5_kms(to_mdp_kms(priv->kms));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MSM_BUS_SCALING
|
||||
#include <mach/board.h>
|
||||
#include <linux/msm-bus.h>
|
||||
#include <linux/msm-bus-board.h>
|
||||
#define MDP_BUS_VECTOR_ENTRY(ab_val, ib_val) \
|
||||
{ \
|
||||
.src = MSM_BUS_MASTER_MDP_PORT0, \
|
||||
.dst = MSM_BUS_SLAVE_EBI_CH0, \
|
||||
.ab = (ab_val), \
|
||||
.ib = (ib_val), \
|
||||
}
|
||||
|
||||
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 = &mdp_bus_vectors[0],
|
||||
}, {
|
||||
.num_paths = 1,
|
||||
.vectors = &mdp_bus_vectors[1],
|
||||
} };
|
||||
static struct msm_bus_scale_pdata mdp_bus_scale_table = {
|
||||
.usecase = mdp_bus_usecases,
|
||||
.num_usecases = ARRAY_SIZE(mdp_bus_usecases),
|
||||
.name = "mdss_mdp",
|
||||
};
|
||||
|
||||
static void bs_init(struct mdp5_cmd_encoder *mdp5_cmd_enc)
|
||||
{
|
||||
mdp5_cmd_enc->bsc = msm_bus_scale_register_client(
|
||||
&mdp_bus_scale_table);
|
||||
DBG("bus scale client: %08x", mdp5_cmd_enc->bsc);
|
||||
}
|
||||
|
||||
static void bs_fini(struct mdp5_cmd_encoder *mdp5_cmd_enc)
|
||||
{
|
||||
if (mdp5_cmd_enc->bsc) {
|
||||
msm_bus_scale_unregister_client(mdp5_cmd_enc->bsc);
|
||||
mdp5_cmd_enc->bsc = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void bs_set(struct mdp5_cmd_encoder *mdp5_cmd_enc, int idx)
|
||||
{
|
||||
if (mdp5_cmd_enc->bsc) {
|
||||
DBG("set bus scaling: %d", idx);
|
||||
/* HACK: scaling down, and then immediately back up
|
||||
* seems to leave things broken (underflow).. so
|
||||
* never disable:
|
||||
*/
|
||||
idx = 1;
|
||||
msm_bus_scale_client_update_request(mdp5_cmd_enc->bsc, idx);
|
||||
}
|
||||
}
|
||||
#else
|
||||
static void bs_init(struct mdp5_cmd_encoder *mdp5_cmd_enc) {}
|
||||
static void bs_fini(struct mdp5_cmd_encoder *mdp5_cmd_enc) {}
|
||||
static void bs_set(struct mdp5_cmd_encoder *mdp5_cmd_enc, int idx) {}
|
||||
#endif
|
||||
|
||||
#define VSYNC_CLK_RATE 19200000
|
||||
static int pingpong_tearcheck_setup(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct mdp5_kms *mdp5_kms = get_kms(encoder);
|
||||
struct device *dev = encoder->dev->dev;
|
||||
u32 total_lines_x100, vclks_line, cfg;
|
||||
long vsync_clk_speed;
|
||||
int pp_id = GET_PING_PONG_ID(mdp5_crtc_get_lm(encoder->crtc));
|
||||
|
||||
if (IS_ERR_OR_NULL(mdp5_kms->vsync_clk)) {
|
||||
dev_err(dev, "vsync_clk is not initialized\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
total_lines_x100 = mode->vtotal * mode->vrefresh;
|
||||
if (!total_lines_x100) {
|
||||
dev_err(dev, "%s: vtotal(%d) or vrefresh(%d) is 0\n",
|
||||
__func__, mode->vtotal, mode->vrefresh);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
vsync_clk_speed = clk_round_rate(mdp5_kms->vsync_clk, VSYNC_CLK_RATE);
|
||||
if (vsync_clk_speed <= 0) {
|
||||
dev_err(dev, "vsync_clk round rate failed %ld\n",
|
||||
vsync_clk_speed);
|
||||
return -EINVAL;
|
||||
}
|
||||
vclks_line = vsync_clk_speed * 100 / total_lines_x100;
|
||||
|
||||
cfg = MDP5_PP_SYNC_CONFIG_VSYNC_COUNTER_EN
|
||||
| MDP5_PP_SYNC_CONFIG_VSYNC_IN_EN;
|
||||
cfg |= MDP5_PP_SYNC_CONFIG_VSYNC_COUNT(vclks_line);
|
||||
|
||||
mdp5_write(mdp5_kms, REG_MDP5_PP_SYNC_CONFIG_VSYNC(pp_id), cfg);
|
||||
mdp5_write(mdp5_kms,
|
||||
REG_MDP5_PP_SYNC_CONFIG_HEIGHT(pp_id), 0xfff0);
|
||||
mdp5_write(mdp5_kms,
|
||||
REG_MDP5_PP_VSYNC_INIT_VAL(pp_id), mode->vdisplay);
|
||||
mdp5_write(mdp5_kms, REG_MDP5_PP_RD_PTR_IRQ(pp_id), mode->vdisplay + 1);
|
||||
mdp5_write(mdp5_kms, REG_MDP5_PP_START_POS(pp_id), mode->vdisplay);
|
||||
mdp5_write(mdp5_kms, REG_MDP5_PP_SYNC_THRESH(pp_id),
|
||||
MDP5_PP_SYNC_THRESH_START(4) |
|
||||
MDP5_PP_SYNC_THRESH_CONTINUE(4));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pingpong_tearcheck_enable(struct drm_encoder *encoder)
|
||||
{
|
||||
struct mdp5_kms *mdp5_kms = get_kms(encoder);
|
||||
int pp_id = GET_PING_PONG_ID(mdp5_crtc_get_lm(encoder->crtc));
|
||||
int ret;
|
||||
|
||||
ret = clk_set_rate(mdp5_kms->vsync_clk,
|
||||
clk_round_rate(mdp5_kms->vsync_clk, VSYNC_CLK_RATE));
|
||||
if (ret) {
|
||||
dev_err(encoder->dev->dev,
|
||||
"vsync_clk clk_set_rate failed, %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
ret = clk_prepare_enable(mdp5_kms->vsync_clk);
|
||||
if (ret) {
|
||||
dev_err(encoder->dev->dev,
|
||||
"vsync_clk clk_prepare_enable failed, %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
mdp5_write(mdp5_kms, REG_MDP5_PP_TEAR_CHECK_EN(pp_id), 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pingpong_tearcheck_disable(struct drm_encoder *encoder)
|
||||
{
|
||||
struct mdp5_kms *mdp5_kms = get_kms(encoder);
|
||||
int pp_id = GET_PING_PONG_ID(mdp5_crtc_get_lm(encoder->crtc));
|
||||
|
||||
mdp5_write(mdp5_kms, REG_MDP5_PP_TEAR_CHECK_EN(pp_id), 0);
|
||||
clk_disable_unprepare(mdp5_kms->vsync_clk);
|
||||
}
|
||||
|
||||
static void mdp5_cmd_encoder_destroy(struct drm_encoder *encoder)
|
||||
{
|
||||
struct mdp5_cmd_encoder *mdp5_cmd_enc = to_mdp5_cmd_encoder(encoder);
|
||||
bs_fini(mdp5_cmd_enc);
|
||||
drm_encoder_cleanup(encoder);
|
||||
kfree(mdp5_cmd_enc);
|
||||
}
|
||||
|
||||
static const struct drm_encoder_funcs mdp5_cmd_encoder_funcs = {
|
||||
.destroy = mdp5_cmd_encoder_destroy,
|
||||
};
|
||||
|
||||
static bool mdp5_cmd_encoder_mode_fixup(struct drm_encoder *encoder,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static void mdp5_cmd_encoder_mode_set(struct drm_encoder *encoder,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct mdp5_cmd_encoder *mdp5_cmd_enc = to_mdp5_cmd_encoder(encoder);
|
||||
|
||||
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);
|
||||
pingpong_tearcheck_setup(encoder, mode);
|
||||
mdp5_crtc_set_intf(encoder->crtc, &mdp5_cmd_enc->intf);
|
||||
}
|
||||
|
||||
static void mdp5_cmd_encoder_disable(struct drm_encoder *encoder)
|
||||
{
|
||||
struct mdp5_cmd_encoder *mdp5_cmd_enc = to_mdp5_cmd_encoder(encoder);
|
||||
struct mdp5_kms *mdp5_kms = get_kms(encoder);
|
||||
struct mdp5_ctl *ctl = mdp5_crtc_get_ctl(encoder->crtc);
|
||||
struct mdp5_interface *intf = &mdp5_cmd_enc->intf;
|
||||
int lm = mdp5_crtc_get_lm(encoder->crtc);
|
||||
|
||||
if (WARN_ON(!mdp5_cmd_enc->enabled))
|
||||
return;
|
||||
|
||||
/* Wait for the last frame done */
|
||||
mdp_irq_wait(&mdp5_kms->base, lm2ppdone(lm));
|
||||
pingpong_tearcheck_disable(encoder);
|
||||
|
||||
mdp5_ctl_set_encoder_state(ctl, false);
|
||||
mdp5_ctl_commit(ctl, mdp_ctl_flush_mask_encoder(intf));
|
||||
|
||||
bs_set(mdp5_cmd_enc, 0);
|
||||
|
||||
mdp5_cmd_enc->enabled = false;
|
||||
}
|
||||
|
||||
static void mdp5_cmd_encoder_enable(struct drm_encoder *encoder)
|
||||
{
|
||||
struct mdp5_cmd_encoder *mdp5_cmd_enc = to_mdp5_cmd_encoder(encoder);
|
||||
struct mdp5_ctl *ctl = mdp5_crtc_get_ctl(encoder->crtc);
|
||||
struct mdp5_interface *intf = &mdp5_cmd_enc->intf;
|
||||
|
||||
if (WARN_ON(mdp5_cmd_enc->enabled))
|
||||
return;
|
||||
|
||||
bs_set(mdp5_cmd_enc, 1);
|
||||
if (pingpong_tearcheck_enable(encoder))
|
||||
return;
|
||||
|
||||
mdp5_ctl_commit(ctl, mdp_ctl_flush_mask_encoder(intf));
|
||||
|
||||
mdp5_ctl_set_encoder_state(ctl, true);
|
||||
|
||||
mdp5_cmd_enc->enabled = true;
|
||||
}
|
||||
|
||||
static const struct drm_encoder_helper_funcs mdp5_cmd_encoder_helper_funcs = {
|
||||
.mode_fixup = mdp5_cmd_encoder_mode_fixup,
|
||||
.mode_set = mdp5_cmd_encoder_mode_set,
|
||||
.disable = mdp5_cmd_encoder_disable,
|
||||
.enable = mdp5_cmd_encoder_enable,
|
||||
};
|
||||
|
||||
int mdp5_cmd_encoder_set_split_display(struct drm_encoder *encoder,
|
||||
struct drm_encoder *slave_encoder)
|
||||
{
|
||||
struct mdp5_cmd_encoder *mdp5_cmd_enc = to_mdp5_cmd_encoder(encoder);
|
||||
struct mdp5_kms *mdp5_kms;
|
||||
int intf_num;
|
||||
u32 data = 0;
|
||||
|
||||
if (!encoder || !slave_encoder)
|
||||
return -EINVAL;
|
||||
|
||||
mdp5_kms = get_kms(encoder);
|
||||
intf_num = mdp5_cmd_enc->intf.num;
|
||||
|
||||
/* Switch slave encoder's trigger MUX, to use the master's
|
||||
* start signal for the slave encoder
|
||||
*/
|
||||
if (intf_num == 1)
|
||||
data |= MDP5_SPLIT_DPL_UPPER_INTF2_SW_TRG_MUX;
|
||||
else if (intf_num == 2)
|
||||
data |= MDP5_SPLIT_DPL_UPPER_INTF1_SW_TRG_MUX;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
/* Smart Panel, Sync mode */
|
||||
data |= MDP5_SPLIT_DPL_UPPER_SMART_PANEL;
|
||||
|
||||
/* Make sure clocks are on when connectors calling this function. */
|
||||
mdp5_enable(mdp5_kms);
|
||||
mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_UPPER, data);
|
||||
|
||||
mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_LOWER,
|
||||
MDP5_SPLIT_DPL_LOWER_SMART_PANEL);
|
||||
mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_EN, 1);
|
||||
mdp5_disable(mdp5_kms);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* initialize command mode encoder */
|
||||
struct drm_encoder *mdp5_cmd_encoder_init(struct drm_device *dev,
|
||||
struct mdp5_interface *intf)
|
||||
{
|
||||
struct drm_encoder *encoder = NULL;
|
||||
struct mdp5_cmd_encoder *mdp5_cmd_enc;
|
||||
int ret;
|
||||
|
||||
if (WARN_ON((intf->type != INTF_DSI) &&
|
||||
(intf->mode != MDP5_INTF_DSI_MODE_COMMAND))) {
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
mdp5_cmd_enc = kzalloc(sizeof(*mdp5_cmd_enc), GFP_KERNEL);
|
||||
if (!mdp5_cmd_enc) {
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
memcpy(&mdp5_cmd_enc->intf, intf, sizeof(mdp5_cmd_enc->intf));
|
||||
encoder = &mdp5_cmd_enc->base;
|
||||
|
||||
drm_encoder_init(dev, encoder, &mdp5_cmd_encoder_funcs,
|
||||
DRM_MODE_ENCODER_DSI);
|
||||
|
||||
drm_encoder_helper_add(encoder, &mdp5_cmd_encoder_helper_funcs);
|
||||
|
||||
bs_init(mdp5_cmd_enc);
|
||||
|
||||
return encoder;
|
||||
|
||||
fail:
|
||||
if (encoder)
|
||||
mdp5_cmd_encoder_destroy(encoder);
|
||||
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
|
@ -82,8 +82,6 @@ static void request_pending(struct drm_crtc *crtc, uint32_t pending)
|
|||
mdp_irq_register(&get_kms(crtc)->base, &mdp5_crtc->vblank);
|
||||
}
|
||||
|
||||
#define mdp5_lm_get_flush(lm) mdp_ctl_flush_mask_lm(lm)
|
||||
|
||||
static void crtc_flush(struct drm_crtc *crtc, u32 flush_mask)
|
||||
{
|
||||
struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
|
||||
|
@ -110,8 +108,8 @@ static void crtc_flush_all(struct drm_crtc *crtc)
|
|||
drm_atomic_crtc_for_each_plane(plane, crtc) {
|
||||
flush_mask |= mdp5_plane_get_flush(plane);
|
||||
}
|
||||
flush_mask |= mdp5_ctl_get_flush(mdp5_crtc->ctl);
|
||||
flush_mask |= mdp5_lm_get_flush(mdp5_crtc->lm);
|
||||
|
||||
flush_mask |= mdp_ctl_flush_mask_lm(mdp5_crtc->lm);
|
||||
|
||||
crtc_flush(crtc, flush_mask);
|
||||
}
|
||||
|
@ -298,8 +296,6 @@ static void mdp5_crtc_enable(struct drm_crtc *crtc)
|
|||
mdp5_enable(mdp5_kms);
|
||||
mdp_irq_register(&mdp5_kms->base, &mdp5_crtc->err);
|
||||
|
||||
crtc_flush_all(crtc);
|
||||
|
||||
mdp5_crtc->enabled = true;
|
||||
}
|
||||
|
||||
|
@ -444,13 +440,14 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
|
|||
struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct mdp5_kms *mdp5_kms = get_kms(crtc);
|
||||
struct drm_gem_object *cursor_bo, *old_bo;
|
||||
struct drm_gem_object *cursor_bo, *old_bo = NULL;
|
||||
uint32_t blendcfg, cursor_addr, stride;
|
||||
int ret, bpp, lm;
|
||||
unsigned int depth;
|
||||
enum mdp5_cursor_alpha cur_alpha = CURSOR_ALPHA_PER_PIXEL;
|
||||
uint32_t flush_mask = mdp_ctl_flush_mask_cursor(0);
|
||||
uint32_t roi_w, roi_h;
|
||||
bool cursor_enable = true;
|
||||
unsigned long flags;
|
||||
|
||||
if ((width > CURSOR_WIDTH) || (height > CURSOR_HEIGHT)) {
|
||||
|
@ -463,7 +460,8 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
|
|||
|
||||
if (!handle) {
|
||||
DBG("Cursor off");
|
||||
return mdp5_ctl_set_cursor(mdp5_crtc->ctl, false);
|
||||
cursor_enable = false;
|
||||
goto set_cursor;
|
||||
}
|
||||
|
||||
cursor_bo = drm_gem_object_lookup(dev, file, handle);
|
||||
|
@ -504,11 +502,14 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
|
|||
|
||||
spin_unlock_irqrestore(&mdp5_crtc->cursor.lock, flags);
|
||||
|
||||
ret = mdp5_ctl_set_cursor(mdp5_crtc->ctl, true);
|
||||
if (ret)
|
||||
set_cursor:
|
||||
ret = mdp5_ctl_set_cursor(mdp5_crtc->ctl, 0, cursor_enable);
|
||||
if (ret) {
|
||||
dev_err(dev->dev, "failed to %sable cursor: %d\n",
|
||||
cursor_enable ? "en" : "dis", ret);
|
||||
goto end;
|
||||
}
|
||||
|
||||
flush_mask |= mdp5_ctl_get_flush(mdp5_crtc->ctl);
|
||||
crtc_flush(crtc, flush_mask);
|
||||
|
||||
end:
|
||||
|
@ -613,64 +614,39 @@ void mdp5_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file)
|
|||
}
|
||||
|
||||
/* set interface for routing crtc->encoder: */
|
||||
void mdp5_crtc_set_intf(struct drm_crtc *crtc, int intf,
|
||||
enum mdp5_intf intf_id)
|
||||
void mdp5_crtc_set_intf(struct drm_crtc *crtc, struct mdp5_interface *intf)
|
||||
{
|
||||
struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
|
||||
struct mdp5_kms *mdp5_kms = get_kms(crtc);
|
||||
uint32_t flush_mask = 0;
|
||||
uint32_t intf_sel;
|
||||
unsigned long flags;
|
||||
int lm = mdp5_crtc_get_lm(crtc);
|
||||
|
||||
/* now that we know what irq's we want: */
|
||||
mdp5_crtc->err.irqmask = intf2err(intf);
|
||||
mdp5_crtc->vblank.irqmask = intf2vblank(intf);
|
||||
mdp5_crtc->err.irqmask = intf2err(intf->num);
|
||||
|
||||
/* Register command mode Pingpong done as vblank for now,
|
||||
* so that atomic commit should wait for it to finish.
|
||||
* Ideally, in the future, we should take rd_ptr done as vblank,
|
||||
* and let atomic commit wait for pingpong done for commond mode.
|
||||
*/
|
||||
if (intf->mode == MDP5_INTF_DSI_MODE_COMMAND)
|
||||
mdp5_crtc->vblank.irqmask = lm2ppdone(lm);
|
||||
else
|
||||
mdp5_crtc->vblank.irqmask = intf2vblank(lm, intf);
|
||||
mdp_irq_update(&mdp5_kms->base);
|
||||
|
||||
spin_lock_irqsave(&mdp5_kms->resource_lock, flags);
|
||||
intf_sel = mdp5_read(mdp5_kms, REG_MDP5_DISP_INTF_SEL);
|
||||
|
||||
switch (intf) {
|
||||
case 0:
|
||||
intf_sel &= ~MDP5_DISP_INTF_SEL_INTF0__MASK;
|
||||
intf_sel |= MDP5_DISP_INTF_SEL_INTF0(intf_id);
|
||||
break;
|
||||
case 1:
|
||||
intf_sel &= ~MDP5_DISP_INTF_SEL_INTF1__MASK;
|
||||
intf_sel |= MDP5_DISP_INTF_SEL_INTF1(intf_id);
|
||||
break;
|
||||
case 2:
|
||||
intf_sel &= ~MDP5_DISP_INTF_SEL_INTF2__MASK;
|
||||
intf_sel |= MDP5_DISP_INTF_SEL_INTF2(intf_id);
|
||||
break;
|
||||
case 3:
|
||||
intf_sel &= ~MDP5_DISP_INTF_SEL_INTF3__MASK;
|
||||
intf_sel |= MDP5_DISP_INTF_SEL_INTF3(intf_id);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
|
||||
mdp5_write(mdp5_kms, REG_MDP5_DISP_INTF_SEL, intf_sel);
|
||||
spin_unlock_irqrestore(&mdp5_kms->resource_lock, flags);
|
||||
|
||||
DBG("%s: intf_sel=%08x", mdp5_crtc->name, intf_sel);
|
||||
mdp5_ctl_set_intf(mdp5_crtc->ctl, intf);
|
||||
flush_mask |= mdp5_ctl_get_flush(mdp5_crtc->ctl);
|
||||
flush_mask |= mdp5_lm_get_flush(mdp5_crtc->lm);
|
||||
|
||||
crtc_flush(crtc, flush_mask);
|
||||
}
|
||||
|
||||
int mdp5_crtc_get_lm(struct drm_crtc *crtc)
|
||||
{
|
||||
struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
|
||||
return WARN_ON(!crtc) ? -EINVAL : mdp5_crtc->lm;
|
||||
}
|
||||
|
||||
if (WARN_ON(!crtc))
|
||||
return -EINVAL;
|
||||
|
||||
return mdp5_crtc->lm;
|
||||
struct mdp5_ctl *mdp5_crtc_get_ctl(struct drm_crtc *crtc)
|
||||
{
|
||||
struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
|
||||
return WARN_ON(!crtc) ? NULL : mdp5_crtc->ctl;
|
||||
}
|
||||
|
||||
/* initialize crtc */
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2014 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2014-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
|
||||
|
@ -33,23 +33,31 @@
|
|||
* requested by the client (in mdp5_crtc_mode_set()).
|
||||
*/
|
||||
|
||||
struct op_mode {
|
||||
struct mdp5_interface intf;
|
||||
|
||||
bool encoder_enabled;
|
||||
uint32_t start_mask;
|
||||
};
|
||||
|
||||
struct mdp5_ctl {
|
||||
struct mdp5_ctl_manager *ctlm;
|
||||
|
||||
u32 id;
|
||||
int lm;
|
||||
|
||||
/* whether this CTL has been allocated or not: */
|
||||
bool busy;
|
||||
|
||||
/* memory output connection (@see mdp5_ctl_mode): */
|
||||
u32 mode;
|
||||
/* Operation Mode Configuration for the Pipeline */
|
||||
struct op_mode pipeline;
|
||||
|
||||
/* REG_MDP5_CTL_*(<id>) registers access info + lock: */
|
||||
spinlock_t hw_lock;
|
||||
u32 reg_offset;
|
||||
|
||||
/* flush mask used to commit CTL registers */
|
||||
u32 flush_mask;
|
||||
/* when do CTL registers need to be flushed? (mask of trigger bits) */
|
||||
u32 pending_ctl_trigger;
|
||||
|
||||
bool cursor_on;
|
||||
|
||||
|
@ -63,6 +71,9 @@ struct mdp5_ctl_manager {
|
|||
u32 nlm;
|
||||
u32 nctl;
|
||||
|
||||
/* to filter out non-present bits in the current hardware config */
|
||||
u32 flush_hw_mask;
|
||||
|
||||
/* pool of CTLs + lock to protect resource allocation (ctls[i].busy) */
|
||||
spinlock_t pool_lock;
|
||||
struct mdp5_ctl ctls[MAX_CTL];
|
||||
|
@ -94,31 +105,172 @@ u32 ctl_read(struct mdp5_ctl *ctl, u32 reg)
|
|||
return mdp5_read(mdp5_kms, reg);
|
||||
}
|
||||
|
||||
|
||||
int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, int intf)
|
||||
static void set_display_intf(struct mdp5_kms *mdp5_kms,
|
||||
struct mdp5_interface *intf)
|
||||
{
|
||||
unsigned long flags;
|
||||
static const enum mdp5_intfnum intfnum[] = {
|
||||
INTF0, INTF1, INTF2, INTF3,
|
||||
};
|
||||
u32 intf_sel;
|
||||
|
||||
spin_lock_irqsave(&mdp5_kms->resource_lock, flags);
|
||||
intf_sel = mdp5_read(mdp5_kms, REG_MDP5_MDP_DISP_INTF_SEL(0));
|
||||
|
||||
switch (intf->num) {
|
||||
case 0:
|
||||
intf_sel &= ~MDP5_MDP_DISP_INTF_SEL_INTF0__MASK;
|
||||
intf_sel |= MDP5_MDP_DISP_INTF_SEL_INTF0(intf->type);
|
||||
break;
|
||||
case 1:
|
||||
intf_sel &= ~MDP5_MDP_DISP_INTF_SEL_INTF1__MASK;
|
||||
intf_sel |= MDP5_MDP_DISP_INTF_SEL_INTF1(intf->type);
|
||||
break;
|
||||
case 2:
|
||||
intf_sel &= ~MDP5_MDP_DISP_INTF_SEL_INTF2__MASK;
|
||||
intf_sel |= MDP5_MDP_DISP_INTF_SEL_INTF2(intf->type);
|
||||
break;
|
||||
case 3:
|
||||
intf_sel &= ~MDP5_MDP_DISP_INTF_SEL_INTF3__MASK;
|
||||
intf_sel |= MDP5_MDP_DISP_INTF_SEL_INTF3(intf->type);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
|
||||
mdp5_write(mdp5_kms, REG_MDP5_MDP_DISP_INTF_SEL(0), intf_sel);
|
||||
spin_unlock_irqrestore(&mdp5_kms->resource_lock, flags);
|
||||
}
|
||||
|
||||
static void set_ctl_op(struct mdp5_ctl *ctl, struct mdp5_interface *intf)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 ctl_op = 0;
|
||||
|
||||
if (!mdp5_cfg_intf_is_virtual(intf->type))
|
||||
ctl_op |= MDP5_CTL_OP_INTF_NUM(INTF0 + intf->num);
|
||||
|
||||
switch (intf->type) {
|
||||
case INTF_DSI:
|
||||
if (intf->mode == MDP5_INTF_DSI_MODE_COMMAND)
|
||||
ctl_op |= MDP5_CTL_OP_CMD_MODE;
|
||||
break;
|
||||
|
||||
case INTF_WB:
|
||||
if (intf->mode == MDP5_INTF_WB_MODE_LINE)
|
||||
ctl_op |= MDP5_CTL_OP_MODE(MODE_WB_2_LINE);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&ctl->hw_lock, flags);
|
||||
ctl_write(ctl, REG_MDP5_CTL_OP(ctl->id),
|
||||
MDP5_CTL_OP_MODE(ctl->mode) |
|
||||
MDP5_CTL_OP_INTF_NUM(intfnum[intf]));
|
||||
ctl_write(ctl, REG_MDP5_CTL_OP(ctl->id), ctl_op);
|
||||
spin_unlock_irqrestore(&ctl->hw_lock, flags);
|
||||
}
|
||||
|
||||
int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, struct mdp5_interface *intf)
|
||||
{
|
||||
struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
|
||||
struct mdp5_kms *mdp5_kms = get_kms(ctl_mgr);
|
||||
|
||||
memcpy(&ctl->pipeline.intf, intf, sizeof(*intf));
|
||||
|
||||
ctl->pipeline.start_mask = mdp_ctl_flush_mask_lm(ctl->lm) |
|
||||
mdp_ctl_flush_mask_encoder(intf);
|
||||
|
||||
/* Virtual interfaces need not set a display intf (e.g.: Writeback) */
|
||||
if (!mdp5_cfg_intf_is_virtual(intf->type))
|
||||
set_display_intf(mdp5_kms, intf);
|
||||
|
||||
set_ctl_op(ctl, intf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, bool enable)
|
||||
static bool start_signal_needed(struct mdp5_ctl *ctl)
|
||||
{
|
||||
struct op_mode *pipeline = &ctl->pipeline;
|
||||
|
||||
if (!pipeline->encoder_enabled || pipeline->start_mask != 0)
|
||||
return false;
|
||||
|
||||
switch (pipeline->intf.type) {
|
||||
case INTF_WB:
|
||||
return true;
|
||||
case INTF_DSI:
|
||||
return pipeline->intf.mode == MDP5_INTF_DSI_MODE_COMMAND;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* send_start_signal() - Overlay Processor Start Signal
|
||||
*
|
||||
* For a given control operation (display pipeline), a START signal needs to be
|
||||
* executed in order to kick off operation and activate all layers.
|
||||
* e.g.: DSI command mode, Writeback
|
||||
*/
|
||||
static void send_start_signal(struct mdp5_ctl *ctl)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ctl->hw_lock, flags);
|
||||
ctl_write(ctl, REG_MDP5_CTL_START(ctl->id), 1);
|
||||
spin_unlock_irqrestore(&ctl->hw_lock, flags);
|
||||
}
|
||||
|
||||
static void refill_start_mask(struct mdp5_ctl *ctl)
|
||||
{
|
||||
struct op_mode *pipeline = &ctl->pipeline;
|
||||
struct mdp5_interface *intf = &ctl->pipeline.intf;
|
||||
|
||||
pipeline->start_mask = mdp_ctl_flush_mask_lm(ctl->lm);
|
||||
|
||||
/*
|
||||
* Writeback encoder needs to program & flush
|
||||
* address registers for each page flip..
|
||||
*/
|
||||
if (intf->type == INTF_WB)
|
||||
pipeline->start_mask |= mdp_ctl_flush_mask_encoder(intf);
|
||||
}
|
||||
|
||||
/**
|
||||
* mdp5_ctl_set_encoder_state() - set the encoder state
|
||||
*
|
||||
* @enable: true, when encoder is ready for data streaming; false, otherwise.
|
||||
*
|
||||
* Note:
|
||||
* This encoder state is needed to trigger START signal (data path kickoff).
|
||||
*/
|
||||
int mdp5_ctl_set_encoder_state(struct mdp5_ctl *ctl, bool enabled)
|
||||
{
|
||||
if (WARN_ON(!ctl))
|
||||
return -EINVAL;
|
||||
|
||||
ctl->pipeline.encoder_enabled = enabled;
|
||||
DBG("intf_%d: %s", ctl->pipeline.intf.num, enabled ? "on" : "off");
|
||||
|
||||
if (start_signal_needed(ctl)) {
|
||||
send_start_signal(ctl);
|
||||
refill_start_mask(ctl);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note:
|
||||
* CTL registers need to be flushed after calling this function
|
||||
* (call mdp5_ctl_commit() with mdp_ctl_flush_mask_ctl() mask)
|
||||
*/
|
||||
int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, int cursor_id, bool enable)
|
||||
{
|
||||
struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
|
||||
unsigned long flags;
|
||||
u32 blend_cfg;
|
||||
int lm;
|
||||
int lm = ctl->lm;
|
||||
|
||||
lm = mdp5_crtc_get_lm(ctl->crtc);
|
||||
if (unlikely(WARN_ON(lm < 0))) {
|
||||
dev_err(ctl_mgr->dev->dev, "CTL %d cannot find LM: %d",
|
||||
ctl->id, lm);
|
||||
|
@ -138,12 +290,12 @@ int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, bool enable)
|
|||
|
||||
spin_unlock_irqrestore(&ctl->hw_lock, flags);
|
||||
|
||||
ctl->pending_ctl_trigger = mdp_ctl_flush_mask_cursor(cursor_id);
|
||||
ctl->cursor_on = enable;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int mdp5_ctl_blend(struct mdp5_ctl *ctl, u32 lm, u32 blend_cfg)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
@ -157,39 +309,124 @@ int mdp5_ctl_blend(struct mdp5_ctl *ctl, u32 lm, u32 blend_cfg)
|
|||
ctl_write(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, lm), blend_cfg);
|
||||
spin_unlock_irqrestore(&ctl->hw_lock, flags);
|
||||
|
||||
ctl->pending_ctl_trigger = mdp_ctl_flush_mask_lm(lm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 mdp_ctl_flush_mask_encoder(struct mdp5_interface *intf)
|
||||
{
|
||||
if (intf->type == INTF_WB)
|
||||
return MDP5_CTL_FLUSH_WB;
|
||||
|
||||
switch (intf->num) {
|
||||
case 0: return MDP5_CTL_FLUSH_TIMING_0;
|
||||
case 1: return MDP5_CTL_FLUSH_TIMING_1;
|
||||
case 2: return MDP5_CTL_FLUSH_TIMING_2;
|
||||
case 3: return MDP5_CTL_FLUSH_TIMING_3;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
u32 mdp_ctl_flush_mask_cursor(int cursor_id)
|
||||
{
|
||||
switch (cursor_id) {
|
||||
case 0: return MDP5_CTL_FLUSH_CURSOR_0;
|
||||
case 1: return MDP5_CTL_FLUSH_CURSOR_1;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
u32 mdp_ctl_flush_mask_pipe(enum mdp5_pipe pipe)
|
||||
{
|
||||
switch (pipe) {
|
||||
case SSPP_VIG0: return MDP5_CTL_FLUSH_VIG0;
|
||||
case SSPP_VIG1: return MDP5_CTL_FLUSH_VIG1;
|
||||
case SSPP_VIG2: return MDP5_CTL_FLUSH_VIG2;
|
||||
case SSPP_RGB0: return MDP5_CTL_FLUSH_RGB0;
|
||||
case SSPP_RGB1: return MDP5_CTL_FLUSH_RGB1;
|
||||
case SSPP_RGB2: return MDP5_CTL_FLUSH_RGB2;
|
||||
case SSPP_DMA0: return MDP5_CTL_FLUSH_DMA0;
|
||||
case SSPP_DMA1: return MDP5_CTL_FLUSH_DMA1;
|
||||
case SSPP_VIG3: return MDP5_CTL_FLUSH_VIG3;
|
||||
case SSPP_RGB3: return MDP5_CTL_FLUSH_RGB3;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
u32 mdp_ctl_flush_mask_lm(int lm)
|
||||
{
|
||||
switch (lm) {
|
||||
case 0: return MDP5_CTL_FLUSH_LM0;
|
||||
case 1: return MDP5_CTL_FLUSH_LM1;
|
||||
case 2: return MDP5_CTL_FLUSH_LM2;
|
||||
case 5: return MDP5_CTL_FLUSH_LM5;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static u32 fix_sw_flush(struct mdp5_ctl *ctl, u32 flush_mask)
|
||||
{
|
||||
struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
|
||||
u32 sw_mask = 0;
|
||||
#define BIT_NEEDS_SW_FIX(bit) \
|
||||
(!(ctl_mgr->flush_hw_mask & bit) && (flush_mask & bit))
|
||||
|
||||
/* for some targets, cursor bit is the same as LM bit */
|
||||
if (BIT_NEEDS_SW_FIX(MDP5_CTL_FLUSH_CURSOR_0))
|
||||
sw_mask |= mdp_ctl_flush_mask_lm(ctl->lm);
|
||||
|
||||
return sw_mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* mdp5_ctl_commit() - Register Flush
|
||||
*
|
||||
* The flush register is used to indicate several registers are all
|
||||
* programmed, and are safe to update to the back copy of the double
|
||||
* buffered registers.
|
||||
*
|
||||
* Some registers FLUSH bits are shared when the hardware does not have
|
||||
* dedicated bits for them; handling these is the job of fix_sw_flush().
|
||||
*
|
||||
* CTL registers need to be flushed in some circumstances; if that is the
|
||||
* case, some trigger bits will be present in both flush mask and
|
||||
* ctl->pending_ctl_trigger.
|
||||
*/
|
||||
int mdp5_ctl_commit(struct mdp5_ctl *ctl, u32 flush_mask)
|
||||
{
|
||||
struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
|
||||
struct op_mode *pipeline = &ctl->pipeline;
|
||||
unsigned long flags;
|
||||
|
||||
if (flush_mask & MDP5_CTL_FLUSH_CURSOR_DUMMY) {
|
||||
int lm = mdp5_crtc_get_lm(ctl->crtc);
|
||||
pipeline->start_mask &= ~flush_mask;
|
||||
|
||||
if (unlikely(WARN_ON(lm < 0))) {
|
||||
dev_err(ctl_mgr->dev->dev, "CTL %d cannot find LM: %d",
|
||||
ctl->id, lm);
|
||||
return -EINVAL;
|
||||
}
|
||||
VERB("flush_mask=%x, start_mask=%x, trigger=%x", flush_mask,
|
||||
pipeline->start_mask, ctl->pending_ctl_trigger);
|
||||
|
||||
/* for current targets, cursor bit is the same as LM bit */
|
||||
flush_mask |= mdp_ctl_flush_mask_lm(lm);
|
||||
if (ctl->pending_ctl_trigger & flush_mask) {
|
||||
flush_mask |= MDP5_CTL_FLUSH_CTL;
|
||||
ctl->pending_ctl_trigger = 0;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&ctl->hw_lock, flags);
|
||||
ctl_write(ctl, REG_MDP5_CTL_FLUSH(ctl->id), flush_mask);
|
||||
spin_unlock_irqrestore(&ctl->hw_lock, flags);
|
||||
flush_mask |= fix_sw_flush(ctl, flush_mask);
|
||||
|
||||
flush_mask &= ctl_mgr->flush_hw_mask;
|
||||
|
||||
if (flush_mask) {
|
||||
spin_lock_irqsave(&ctl->hw_lock, flags);
|
||||
ctl_write(ctl, REG_MDP5_CTL_FLUSH(ctl->id), flush_mask);
|
||||
spin_unlock_irqrestore(&ctl->hw_lock, flags);
|
||||
}
|
||||
|
||||
if (start_signal_needed(ctl)) {
|
||||
send_start_signal(ctl);
|
||||
refill_start_mask(ctl);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 mdp5_ctl_get_flush(struct mdp5_ctl *ctl)
|
||||
{
|
||||
return ctl->flush_mask;
|
||||
}
|
||||
|
||||
void mdp5_ctl_release(struct mdp5_ctl *ctl)
|
||||
{
|
||||
struct mdp5_ctl_manager *ctl_mgr = ctl->ctlm;
|
||||
|
@ -208,6 +445,11 @@ void mdp5_ctl_release(struct mdp5_ctl *ctl)
|
|||
DBG("CTL %d released", ctl->id);
|
||||
}
|
||||
|
||||
int mdp5_ctl_get_ctl_id(struct mdp5_ctl *ctl)
|
||||
{
|
||||
return WARN_ON(!ctl) ? -EINVAL : ctl->id;
|
||||
}
|
||||
|
||||
/*
|
||||
* mdp5_ctl_request() - CTL dynamic allocation
|
||||
*
|
||||
|
@ -235,8 +477,10 @@ struct mdp5_ctl *mdp5_ctlm_request(struct mdp5_ctl_manager *ctl_mgr,
|
|||
|
||||
ctl = &ctl_mgr->ctls[c];
|
||||
|
||||
ctl->lm = mdp5_crtc_get_lm(crtc);
|
||||
ctl->crtc = crtc;
|
||||
ctl->busy = true;
|
||||
ctl->pending_ctl_trigger = 0;
|
||||
DBG("CTL %d allocated", ctl->id);
|
||||
|
||||
unlock:
|
||||
|
@ -267,7 +511,7 @@ struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev,
|
|||
void __iomem *mmio_base, const struct mdp5_cfg_hw *hw_cfg)
|
||||
{
|
||||
struct mdp5_ctl_manager *ctl_mgr;
|
||||
const struct mdp5_sub_block *ctl_cfg = &hw_cfg->ctl;
|
||||
const struct mdp5_ctl_block *ctl_cfg = &hw_cfg->ctl;
|
||||
unsigned long flags;
|
||||
int c, ret;
|
||||
|
||||
|
@ -289,6 +533,7 @@ struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev,
|
|||
ctl_mgr->dev = dev;
|
||||
ctl_mgr->nlm = hw_cfg->lm.count;
|
||||
ctl_mgr->nctl = ctl_cfg->count;
|
||||
ctl_mgr->flush_hw_mask = ctl_cfg->flush_hw_mask;
|
||||
spin_lock_init(&ctl_mgr->pool_lock);
|
||||
|
||||
/* initialize each CTL of the pool: */
|
||||
|
@ -303,9 +548,7 @@ struct mdp5_ctl_manager *mdp5_ctlm_init(struct drm_device *dev,
|
|||
}
|
||||
ctl->ctlm = ctl_mgr;
|
||||
ctl->id = c;
|
||||
ctl->mode = MODE_NONE;
|
||||
ctl->reg_offset = ctl_cfg->base[c];
|
||||
ctl->flush_mask = MDP5_CTL_FLUSH_CTL;
|
||||
ctl->busy = false;
|
||||
spin_lock_init(&ctl->hw_lock);
|
||||
}
|
||||
|
|
|
@ -33,19 +33,13 @@ void mdp5_ctlm_destroy(struct mdp5_ctl_manager *ctlm);
|
|||
* which is then used to call the other mdp5_ctl_*(ctl, ...) functions.
|
||||
*/
|
||||
struct mdp5_ctl *mdp5_ctlm_request(struct mdp5_ctl_manager *ctlm, struct drm_crtc *crtc);
|
||||
int mdp5_ctl_get_ctl_id(struct mdp5_ctl *ctl);
|
||||
|
||||
int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, int intf);
|
||||
struct mdp5_interface;
|
||||
int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, struct mdp5_interface *intf);
|
||||
int mdp5_ctl_set_encoder_state(struct mdp5_ctl *ctl, bool enabled);
|
||||
|
||||
int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, bool enable);
|
||||
|
||||
/* @blend_cfg: see LM blender config definition below */
|
||||
int mdp5_ctl_blend(struct mdp5_ctl *ctl, u32 lm, u32 blend_cfg);
|
||||
|
||||
/* @flush_mask: see CTL flush masks definitions below */
|
||||
int mdp5_ctl_commit(struct mdp5_ctl *ctl, u32 flush_mask);
|
||||
u32 mdp5_ctl_get_flush(struct mdp5_ctl *ctl);
|
||||
|
||||
void mdp5_ctl_release(struct mdp5_ctl *ctl);
|
||||
int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, int cursor_id, bool enable);
|
||||
|
||||
/*
|
||||
* blend_cfg (LM blender config):
|
||||
|
@ -72,51 +66,32 @@ static inline u32 mdp_ctl_blend_mask(enum mdp5_pipe pipe,
|
|||
}
|
||||
|
||||
/*
|
||||
* flush_mask (CTL flush masks):
|
||||
* mdp5_ctl_blend() - Blend multiple layers on a Layer Mixer (LM)
|
||||
*
|
||||
* The following functions allow each DRM entity to get and store
|
||||
* their own flush mask.
|
||||
* Once stored, these masks will then be accessed through each DRM's
|
||||
* interface and used by the caller of mdp5_ctl_commit() to specify
|
||||
* which block(s) need to be flushed through @flush_mask parameter.
|
||||
* @blend_cfg: see LM blender config definition below
|
||||
*
|
||||
* Note:
|
||||
* CTL registers need to be flushed after calling this function
|
||||
* (call mdp5_ctl_commit() with mdp_ctl_flush_mask_ctl() mask)
|
||||
*/
|
||||
int mdp5_ctl_blend(struct mdp5_ctl *ctl, u32 lm, u32 blend_cfg);
|
||||
|
||||
#define MDP5_CTL_FLUSH_CURSOR_DUMMY 0x80000000
|
||||
/**
|
||||
* mdp_ctl_flush_mask...() - Register FLUSH masks
|
||||
*
|
||||
* These masks are used to specify which block(s) need to be flushed
|
||||
* through @flush_mask parameter in mdp5_ctl_commit(.., flush_mask).
|
||||
*/
|
||||
u32 mdp_ctl_flush_mask_lm(int lm);
|
||||
u32 mdp_ctl_flush_mask_pipe(enum mdp5_pipe pipe);
|
||||
u32 mdp_ctl_flush_mask_cursor(int cursor_id);
|
||||
u32 mdp_ctl_flush_mask_encoder(struct mdp5_interface *intf);
|
||||
|
||||
static inline u32 mdp_ctl_flush_mask_cursor(int cursor_id)
|
||||
{
|
||||
/* TODO: use id once multiple cursor support is present */
|
||||
(void)cursor_id;
|
||||
/* @flush_mask: see CTL flush masks definitions below */
|
||||
int mdp5_ctl_commit(struct mdp5_ctl *ctl, u32 flush_mask);
|
||||
|
||||
return MDP5_CTL_FLUSH_CURSOR_DUMMY;
|
||||
}
|
||||
void mdp5_ctl_release(struct mdp5_ctl *ctl);
|
||||
|
||||
static inline u32 mdp_ctl_flush_mask_lm(int lm)
|
||||
{
|
||||
switch (lm) {
|
||||
case 0: return MDP5_CTL_FLUSH_LM0;
|
||||
case 1: return MDP5_CTL_FLUSH_LM1;
|
||||
case 2: return MDP5_CTL_FLUSH_LM2;
|
||||
case 5: return MDP5_CTL_FLUSH_LM5;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline u32 mdp_ctl_flush_mask_pipe(enum mdp5_pipe pipe)
|
||||
{
|
||||
switch (pipe) {
|
||||
case SSPP_VIG0: return MDP5_CTL_FLUSH_VIG0;
|
||||
case SSPP_VIG1: return MDP5_CTL_FLUSH_VIG1;
|
||||
case SSPP_VIG2: return MDP5_CTL_FLUSH_VIG2;
|
||||
case SSPP_RGB0: return MDP5_CTL_FLUSH_RGB0;
|
||||
case SSPP_RGB1: return MDP5_CTL_FLUSH_RGB1;
|
||||
case SSPP_RGB2: return MDP5_CTL_FLUSH_RGB2;
|
||||
case SSPP_DMA0: return MDP5_CTL_FLUSH_DMA0;
|
||||
case SSPP_DMA1: return MDP5_CTL_FLUSH_DMA1;
|
||||
case SSPP_VIG3: return MDP5_CTL_FLUSH_VIG3;
|
||||
case SSPP_RGB3: return MDP5_CTL_FLUSH_RGB3;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __MDP5_CTL_H__ */
|
||||
|
|
|
@ -23,8 +23,7 @@
|
|||
|
||||
struct mdp5_encoder {
|
||||
struct drm_encoder base;
|
||||
int intf;
|
||||
enum mdp5_intf intf_id;
|
||||
struct mdp5_interface intf;
|
||||
spinlock_t intf_lock; /* protect REG_MDP5_INTF_* registers */
|
||||
bool enabled;
|
||||
uint32_t bsc;
|
||||
|
@ -126,7 +125,7 @@ static void mdp5_encoder_mode_set(struct drm_encoder *encoder,
|
|||
struct mdp5_kms *mdp5_kms = get_kms(encoder);
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_connector *connector;
|
||||
int intf = mdp5_encoder->intf;
|
||||
int intf = mdp5_encoder->intf.num;
|
||||
uint32_t dtv_hsync_skew, vsync_period, vsync_len, ctrl_pol;
|
||||
uint32_t display_v_start, display_v_end;
|
||||
uint32_t hsync_start_x, hsync_end_x;
|
||||
|
@ -188,7 +187,7 @@ static void mdp5_encoder_mode_set(struct drm_encoder *encoder,
|
|||
* DISPLAY_V_START = (VBP * HCYCLE) + HBP
|
||||
* DISPLAY_V_END = (VBP + VACTIVE) * HCYCLE - 1 - HFP
|
||||
*/
|
||||
if (mdp5_encoder->intf_id == INTF_eDP) {
|
||||
if (mdp5_encoder->intf.type == INTF_eDP) {
|
||||
display_v_start += mode->htotal - mode->hsync_start;
|
||||
display_v_end -= mode->hsync_start - mode->hdisplay;
|
||||
}
|
||||
|
@ -218,21 +217,29 @@ static void mdp5_encoder_mode_set(struct drm_encoder *encoder,
|
|||
mdp5_write(mdp5_kms, REG_MDP5_INTF_FRAME_LINE_COUNT_EN(intf), 0x3); /* frame+line? */
|
||||
|
||||
spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags);
|
||||
|
||||
mdp5_crtc_set_intf(encoder->crtc, &mdp5_encoder->intf);
|
||||
}
|
||||
|
||||
static void mdp5_encoder_disable(struct drm_encoder *encoder)
|
||||
{
|
||||
struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
|
||||
struct mdp5_kms *mdp5_kms = get_kms(encoder);
|
||||
int intf = mdp5_encoder->intf;
|
||||
struct mdp5_ctl *ctl = mdp5_crtc_get_ctl(encoder->crtc);
|
||||
int lm = mdp5_crtc_get_lm(encoder->crtc);
|
||||
struct mdp5_interface *intf = &mdp5_encoder->intf;
|
||||
int intfn = mdp5_encoder->intf.num;
|
||||
unsigned long flags;
|
||||
|
||||
if (WARN_ON(!mdp5_encoder->enabled))
|
||||
return;
|
||||
|
||||
mdp5_ctl_set_encoder_state(ctl, false);
|
||||
|
||||
spin_lock_irqsave(&mdp5_encoder->intf_lock, flags);
|
||||
mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intf), 0);
|
||||
mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intfn), 0);
|
||||
spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags);
|
||||
mdp5_ctl_commit(ctl, mdp_ctl_flush_mask_encoder(intf));
|
||||
|
||||
/*
|
||||
* Wait for a vsync so we know the ENABLE=0 latched before
|
||||
|
@ -242,7 +249,7 @@ static void mdp5_encoder_disable(struct drm_encoder *encoder)
|
|||
* the settings changes for the new modeset (like new
|
||||
* scanout buffer) don't latch properly..
|
||||
*/
|
||||
mdp_irq_wait(&mdp5_kms->base, intf2vblank(intf));
|
||||
mdp_irq_wait(&mdp5_kms->base, intf2vblank(lm, intf));
|
||||
|
||||
bs_set(mdp5_encoder, 0);
|
||||
|
||||
|
@ -253,19 +260,21 @@ static void mdp5_encoder_enable(struct drm_encoder *encoder)
|
|||
{
|
||||
struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
|
||||
struct mdp5_kms *mdp5_kms = get_kms(encoder);
|
||||
int intf = mdp5_encoder->intf;
|
||||
struct mdp5_ctl *ctl = mdp5_crtc_get_ctl(encoder->crtc);
|
||||
struct mdp5_interface *intf = &mdp5_encoder->intf;
|
||||
int intfn = mdp5_encoder->intf.num;
|
||||
unsigned long flags;
|
||||
|
||||
if (WARN_ON(mdp5_encoder->enabled))
|
||||
return;
|
||||
|
||||
mdp5_crtc_set_intf(encoder->crtc, mdp5_encoder->intf,
|
||||
mdp5_encoder->intf_id);
|
||||
|
||||
bs_set(mdp5_encoder, 1);
|
||||
spin_lock_irqsave(&mdp5_encoder->intf_lock, flags);
|
||||
mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intf), 1);
|
||||
mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intfn), 1);
|
||||
spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags);
|
||||
mdp5_ctl_commit(ctl, mdp_ctl_flush_mask_encoder(intf));
|
||||
|
||||
mdp5_ctl_set_encoder_state(ctl, true);
|
||||
|
||||
mdp5_encoder->enabled = true;
|
||||
}
|
||||
|
@ -277,12 +286,51 @@ static const struct drm_encoder_helper_funcs mdp5_encoder_helper_funcs = {
|
|||
.enable = mdp5_encoder_enable,
|
||||
};
|
||||
|
||||
int mdp5_encoder_set_split_display(struct drm_encoder *encoder,
|
||||
struct drm_encoder *slave_encoder)
|
||||
{
|
||||
struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
|
||||
struct mdp5_kms *mdp5_kms;
|
||||
int intf_num;
|
||||
u32 data = 0;
|
||||
|
||||
if (!encoder || !slave_encoder)
|
||||
return -EINVAL;
|
||||
|
||||
mdp5_kms = get_kms(encoder);
|
||||
intf_num = mdp5_encoder->intf.num;
|
||||
|
||||
/* Switch slave encoder's TimingGen Sync mode,
|
||||
* to use the master's enable signal for the slave encoder.
|
||||
*/
|
||||
if (intf_num == 1)
|
||||
data |= MDP5_SPLIT_DPL_LOWER_INTF2_TG_SYNC;
|
||||
else if (intf_num == 2)
|
||||
data |= MDP5_SPLIT_DPL_LOWER_INTF1_TG_SYNC;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
/* Make sure clocks are on when connectors calling this function. */
|
||||
mdp5_enable(mdp5_kms);
|
||||
mdp5_write(mdp5_kms, REG_MDP5_MDP_SPARE_0(0),
|
||||
MDP5_MDP_SPARE_0_SPLIT_DPL_SINGLE_FLUSH_EN);
|
||||
/* Dumb Panel, Sync mode */
|
||||
mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_UPPER, 0);
|
||||
mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_LOWER, data);
|
||||
mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_EN, 1);
|
||||
mdp5_disable(mdp5_kms);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* initialize encoder */
|
||||
struct drm_encoder *mdp5_encoder_init(struct drm_device *dev, int intf,
|
||||
enum mdp5_intf intf_id)
|
||||
struct drm_encoder *mdp5_encoder_init(struct drm_device *dev,
|
||||
struct mdp5_interface *intf)
|
||||
{
|
||||
struct drm_encoder *encoder = NULL;
|
||||
struct mdp5_encoder *mdp5_encoder;
|
||||
int enc_type = (intf->type == INTF_DSI) ?
|
||||
DRM_MODE_ENCODER_DSI : DRM_MODE_ENCODER_TMDS;
|
||||
int ret;
|
||||
|
||||
mdp5_encoder = kzalloc(sizeof(*mdp5_encoder), GFP_KERNEL);
|
||||
|
@ -291,14 +339,13 @@ struct drm_encoder *mdp5_encoder_init(struct drm_device *dev, int intf,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
mdp5_encoder->intf = intf;
|
||||
mdp5_encoder->intf_id = intf_id;
|
||||
memcpy(&mdp5_encoder->intf, intf, sizeof(mdp5_encoder->intf));
|
||||
encoder = &mdp5_encoder->base;
|
||||
|
||||
spin_lock_init(&mdp5_encoder->intf_lock);
|
||||
|
||||
drm_encoder_init(dev, encoder, &mdp5_encoder_funcs,
|
||||
DRM_MODE_ENCODER_TMDS);
|
||||
drm_encoder_init(dev, encoder, &mdp5_encoder_funcs, enc_type);
|
||||
|
||||
drm_encoder_helper_add(encoder, &mdp5_encoder_helper_funcs);
|
||||
|
||||
bs_init(mdp5_encoder);
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
void mdp5_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask)
|
||||
{
|
||||
mdp5_write(to_mdp5_kms(mdp_kms), REG_MDP5_INTR_EN, irqmask);
|
||||
mdp5_write(to_mdp5_kms(mdp_kms), REG_MDP5_MDP_INTR_EN(0), irqmask);
|
||||
}
|
||||
|
||||
static void mdp5_irq_error_handler(struct mdp_irq *irq, uint32_t irqstatus)
|
||||
|
@ -35,8 +35,8 @@ void mdp5_irq_preinstall(struct msm_kms *kms)
|
|||
{
|
||||
struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
|
||||
mdp5_enable(mdp5_kms);
|
||||
mdp5_write(mdp5_kms, REG_MDP5_INTR_CLEAR, 0xffffffff);
|
||||
mdp5_write(mdp5_kms, REG_MDP5_INTR_EN, 0x00000000);
|
||||
mdp5_write(mdp5_kms, REG_MDP5_MDP_INTR_CLEAR(0), 0xffffffff);
|
||||
mdp5_write(mdp5_kms, REG_MDP5_MDP_INTR_EN(0), 0x00000000);
|
||||
mdp5_disable(mdp5_kms);
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,7 @@ void mdp5_irq_uninstall(struct msm_kms *kms)
|
|||
{
|
||||
struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
|
||||
mdp5_enable(mdp5_kms);
|
||||
mdp5_write(mdp5_kms, REG_MDP5_INTR_EN, 0x00000000);
|
||||
mdp5_write(mdp5_kms, REG_MDP5_MDP_INTR_EN(0), 0x00000000);
|
||||
mdp5_disable(mdp5_kms);
|
||||
}
|
||||
|
||||
|
@ -73,8 +73,8 @@ static void mdp5_irq_mdp(struct mdp_kms *mdp_kms)
|
|||
unsigned int id;
|
||||
uint32_t status;
|
||||
|
||||
status = mdp5_read(mdp5_kms, REG_MDP5_INTR_STATUS);
|
||||
mdp5_write(mdp5_kms, REG_MDP5_INTR_CLEAR, status);
|
||||
status = mdp5_read(mdp5_kms, REG_MDP5_MDP_INTR_STATUS(0));
|
||||
mdp5_write(mdp5_kms, REG_MDP5_MDP_INTR_CLEAR(0), status);
|
||||
|
||||
VERB("status=%08x", status);
|
||||
|
||||
|
@ -91,13 +91,13 @@ irqreturn_t mdp5_irq(struct msm_kms *kms)
|
|||
struct mdp5_kms *mdp5_kms = to_mdp5_kms(mdp_kms);
|
||||
uint32_t intr;
|
||||
|
||||
intr = mdp5_read(mdp5_kms, REG_MDP5_HW_INTR_STATUS);
|
||||
intr = mdp5_read(mdp5_kms, REG_MDSS_HW_INTR_STATUS);
|
||||
|
||||
VERB("intr=%08x", intr);
|
||||
|
||||
if (intr & MDP5_HW_INTR_STATUS_INTR_MDP) {
|
||||
if (intr & MDSS_HW_INTR_STATUS_INTR_MDP) {
|
||||
mdp5_irq_mdp(mdp_kms);
|
||||
intr &= ~MDP5_HW_INTR_STATUS_INTR_MDP;
|
||||
intr &= ~MDSS_HW_INTR_STATUS_INTR_MDP;
|
||||
}
|
||||
|
||||
while (intr) {
|
||||
|
@ -128,10 +128,10 @@ void mdp5_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)
|
|||
* can register to get their irq's delivered
|
||||
*/
|
||||
|
||||
#define VALID_IRQS (MDP5_HW_INTR_STATUS_INTR_DSI0 | \
|
||||
MDP5_HW_INTR_STATUS_INTR_DSI1 | \
|
||||
MDP5_HW_INTR_STATUS_INTR_HDMI | \
|
||||
MDP5_HW_INTR_STATUS_INTR_EDP)
|
||||
#define VALID_IRQS (MDSS_HW_INTR_STATUS_INTR_DSI0 | \
|
||||
MDSS_HW_INTR_STATUS_INTR_DSI1 | \
|
||||
MDSS_HW_INTR_STATUS_INTR_HDMI | \
|
||||
MDSS_HW_INTR_STATUS_INTR_EDP)
|
||||
|
||||
static void mdp5_hw_mask_irq(struct irq_data *irqd)
|
||||
{
|
||||
|
|
|
@ -58,7 +58,7 @@ static int mdp5_hw_init(struct msm_kms *kms)
|
|||
*/
|
||||
|
||||
spin_lock_irqsave(&mdp5_kms->resource_lock, flags);
|
||||
mdp5_write(mdp5_kms, REG_MDP5_DISP_INTF_SEL, 0);
|
||||
mdp5_write(mdp5_kms, REG_MDP5_MDP_DISP_INTF_SEL(0), 0);
|
||||
spin_unlock_irqrestore(&mdp5_kms->resource_lock, flags);
|
||||
|
||||
mdp5_ctlm_hw_reset(mdp5_kms->ctlm);
|
||||
|
@ -86,6 +86,18 @@ static long mdp5_round_pixclk(struct msm_kms *kms, unsigned long rate,
|
|||
return rate;
|
||||
}
|
||||
|
||||
static int mdp5_set_split_display(struct msm_kms *kms,
|
||||
struct drm_encoder *encoder,
|
||||
struct drm_encoder *slave_encoder,
|
||||
bool is_cmd_mode)
|
||||
{
|
||||
if (is_cmd_mode)
|
||||
return mdp5_cmd_encoder_set_split_display(encoder,
|
||||
slave_encoder);
|
||||
else
|
||||
return mdp5_encoder_set_split_display(encoder, slave_encoder);
|
||||
}
|
||||
|
||||
static void mdp5_preclose(struct msm_kms *kms, struct drm_file *file)
|
||||
{
|
||||
struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
|
||||
|
@ -131,6 +143,7 @@ static const struct mdp_kms_funcs kms_funcs = {
|
|||
.complete_commit = mdp5_complete_commit,
|
||||
.get_format = mdp_get_format,
|
||||
.round_pixclk = mdp5_round_pixclk,
|
||||
.set_split_display = mdp5_set_split_display,
|
||||
.preclose = mdp5_preclose,
|
||||
.destroy = mdp5_destroy,
|
||||
},
|
||||
|
@ -161,6 +174,134 @@ int mdp5_enable(struct mdp5_kms *mdp5_kms)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct drm_encoder *construct_encoder(struct mdp5_kms *mdp5_kms,
|
||||
enum mdp5_intf_type intf_type, int intf_num,
|
||||
enum mdp5_intf_mode intf_mode)
|
||||
{
|
||||
struct drm_device *dev = mdp5_kms->dev;
|
||||
struct msm_drm_private *priv = dev->dev_private;
|
||||
struct drm_encoder *encoder;
|
||||
struct mdp5_interface intf = {
|
||||
.num = intf_num,
|
||||
.type = intf_type,
|
||||
.mode = intf_mode,
|
||||
};
|
||||
|
||||
if ((intf_type == INTF_DSI) &&
|
||||
(intf_mode == MDP5_INTF_DSI_MODE_COMMAND))
|
||||
encoder = mdp5_cmd_encoder_init(dev, &intf);
|
||||
else
|
||||
encoder = mdp5_encoder_init(dev, &intf);
|
||||
|
||||
if (IS_ERR(encoder)) {
|
||||
dev_err(dev->dev, "failed to construct encoder\n");
|
||||
return encoder;
|
||||
}
|
||||
|
||||
encoder->possible_crtcs = (1 << priv->num_crtcs) - 1;
|
||||
priv->encoders[priv->num_encoders++] = encoder;
|
||||
|
||||
return encoder;
|
||||
}
|
||||
|
||||
static int get_dsi_id_from_intf(const struct mdp5_cfg_hw *hw_cfg, int intf_num)
|
||||
{
|
||||
const int intf_cnt = hw_cfg->intf.count;
|
||||
const u32 *intfs = hw_cfg->intfs;
|
||||
int id = 0, i;
|
||||
|
||||
for (i = 0; i < intf_cnt; i++) {
|
||||
if (intfs[i] == INTF_DSI) {
|
||||
if (intf_num == i)
|
||||
return id;
|
||||
|
||||
id++;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int modeset_init_intf(struct mdp5_kms *mdp5_kms, int intf_num)
|
||||
{
|
||||
struct drm_device *dev = mdp5_kms->dev;
|
||||
struct msm_drm_private *priv = dev->dev_private;
|
||||
const struct mdp5_cfg_hw *hw_cfg =
|
||||
mdp5_cfg_get_hw_config(mdp5_kms->cfg);
|
||||
enum mdp5_intf_type intf_type = hw_cfg->intfs[intf_num];
|
||||
struct drm_encoder *encoder;
|
||||
int ret = 0;
|
||||
|
||||
switch (intf_type) {
|
||||
case INTF_DISABLED:
|
||||
break;
|
||||
case INTF_eDP:
|
||||
if (!priv->edp)
|
||||
break;
|
||||
|
||||
encoder = construct_encoder(mdp5_kms, INTF_eDP, intf_num,
|
||||
MDP5_INTF_MODE_NONE);
|
||||
if (IS_ERR(encoder)) {
|
||||
ret = PTR_ERR(encoder);
|
||||
break;
|
||||
}
|
||||
|
||||
ret = msm_edp_modeset_init(priv->edp, dev, encoder);
|
||||
break;
|
||||
case INTF_HDMI:
|
||||
if (!priv->hdmi)
|
||||
break;
|
||||
|
||||
encoder = construct_encoder(mdp5_kms, INTF_HDMI, intf_num,
|
||||
MDP5_INTF_MODE_NONE);
|
||||
if (IS_ERR(encoder)) {
|
||||
ret = PTR_ERR(encoder);
|
||||
break;
|
||||
}
|
||||
|
||||
ret = hdmi_modeset_init(priv->hdmi, dev, encoder);
|
||||
break;
|
||||
case INTF_DSI:
|
||||
{
|
||||
int dsi_id = get_dsi_id_from_intf(hw_cfg, intf_num);
|
||||
struct drm_encoder *dsi_encs[MSM_DSI_ENCODER_NUM];
|
||||
enum mdp5_intf_mode mode;
|
||||
int i;
|
||||
|
||||
if ((dsi_id >= ARRAY_SIZE(priv->dsi)) || (dsi_id < 0)) {
|
||||
dev_err(dev->dev, "failed to find dsi from intf %d\n",
|
||||
intf_num);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!priv->dsi[dsi_id])
|
||||
break;
|
||||
|
||||
for (i = 0; i < MSM_DSI_ENCODER_NUM; i++) {
|
||||
mode = (i == MSM_DSI_CMD_ENCODER_ID) ?
|
||||
MDP5_INTF_DSI_MODE_COMMAND :
|
||||
MDP5_INTF_DSI_MODE_VIDEO;
|
||||
dsi_encs[i] = construct_encoder(mdp5_kms, INTF_DSI,
|
||||
intf_num, mode);
|
||||
if (IS_ERR(dsi_encs)) {
|
||||
ret = PTR_ERR(dsi_encs);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ret = msm_dsi_modeset_init(priv->dsi[dsi_id], dev, dsi_encs);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
dev_err(dev->dev, "unknown intf: %d\n", intf_type);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int modeset_init(struct mdp5_kms *mdp5_kms)
|
||||
{
|
||||
static const enum mdp5_pipe crtcs[] = {
|
||||
|
@ -171,7 +312,6 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
|
|||
};
|
||||
struct drm_device *dev = mdp5_kms->dev;
|
||||
struct msm_drm_private *priv = dev->dev_private;
|
||||
struct drm_encoder *encoder;
|
||||
const struct mdp5_cfg_hw *hw_cfg;
|
||||
int i, ret;
|
||||
|
||||
|
@ -222,44 +362,13 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
|
|||
}
|
||||
}
|
||||
|
||||
if (priv->hdmi) {
|
||||
/* Construct encoder for HDMI: */
|
||||
encoder = mdp5_encoder_init(dev, 3, INTF_HDMI);
|
||||
if (IS_ERR(encoder)) {
|
||||
dev_err(dev->dev, "failed to construct encoder\n");
|
||||
ret = PTR_ERR(encoder);
|
||||
/* Construct encoders and modeset initialize connector devices
|
||||
* for each external display interface.
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(hw_cfg->intfs); i++) {
|
||||
ret = modeset_init_intf(mdp5_kms, i);
|
||||
if (ret)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
encoder->possible_crtcs = (1 << priv->num_crtcs) - 1;;
|
||||
priv->encoders[priv->num_encoders++] = encoder;
|
||||
|
||||
ret = hdmi_modeset_init(priv->hdmi, dev, encoder);
|
||||
if (ret) {
|
||||
dev_err(dev->dev, "failed to initialize HDMI: %d\n", ret);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (priv->edp) {
|
||||
/* Construct encoder for eDP: */
|
||||
encoder = mdp5_encoder_init(dev, 0, INTF_eDP);
|
||||
if (IS_ERR(encoder)) {
|
||||
dev_err(dev->dev, "failed to construct eDP encoder\n");
|
||||
ret = PTR_ERR(encoder);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
encoder->possible_crtcs = (1 << priv->num_crtcs) - 1;
|
||||
priv->encoders[priv->num_encoders++] = encoder;
|
||||
|
||||
/* Construct bridge/connector for eDP: */
|
||||
ret = msm_edp_modeset_init(priv->edp, dev, encoder);
|
||||
if (ret) {
|
||||
dev_err(dev->dev, "failed to initialize eDP: %d\n",
|
||||
ret);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -274,11 +383,11 @@ static void read_hw_revision(struct mdp5_kms *mdp5_kms,
|
|||
uint32_t version;
|
||||
|
||||
mdp5_enable(mdp5_kms);
|
||||
version = mdp5_read(mdp5_kms, REG_MDP5_MDP_VERSION);
|
||||
version = mdp5_read(mdp5_kms, REG_MDSS_HW_VERSION);
|
||||
mdp5_disable(mdp5_kms);
|
||||
|
||||
*major = FIELD(version, MDP5_MDP_VERSION_MAJOR);
|
||||
*minor = FIELD(version, MDP5_MDP_VERSION_MINOR);
|
||||
*major = FIELD(version, MDSS_HW_VERSION_MAJOR);
|
||||
*minor = FIELD(version, MDSS_HW_VERSION_MINOR);
|
||||
|
||||
DBG("MDP5 version v%d.%d", *major, *minor);
|
||||
}
|
||||
|
@ -321,6 +430,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
|
|||
|
||||
mdp5_kms->dev = dev;
|
||||
|
||||
/* mdp5_kms->mmio actually represents the MDSS base address */
|
||||
mdp5_kms->mmio = msm_ioremap(pdev, "mdp_phys", "MDP5");
|
||||
if (IS_ERR(mdp5_kms->mmio)) {
|
||||
ret = PTR_ERR(mdp5_kms->mmio);
|
||||
|
@ -403,8 +513,12 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
|
|||
* we don't disable):
|
||||
*/
|
||||
mdp5_enable(mdp5_kms);
|
||||
for (i = 0; i < config->hw->intf.count; i++)
|
||||
for (i = 0; i < MDP5_INTF_NUM_MAX; i++) {
|
||||
if (!config->hw->intf.base[i] ||
|
||||
mdp5_cfg_intf_is_virtual(config->hw->intfs[i]))
|
||||
continue;
|
||||
mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(i), 0);
|
||||
}
|
||||
mdp5_disable(mdp5_kms);
|
||||
mdelay(16);
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ struct mdp5_kms {
|
|||
|
||||
/*
|
||||
* lock to protect access to global resources: ie., following register:
|
||||
* - REG_MDP5_DISP_INTF_SEL
|
||||
* - REG_MDP5_MDP_DISP_INTF_SEL
|
||||
*/
|
||||
spinlock_t resource_lock;
|
||||
|
||||
|
@ -94,6 +94,24 @@ struct mdp5_plane_state {
|
|||
#define to_mdp5_plane_state(x) \
|
||||
container_of(x, struct mdp5_plane_state, base)
|
||||
|
||||
enum mdp5_intf_mode {
|
||||
MDP5_INTF_MODE_NONE = 0,
|
||||
|
||||
/* Modes used for DSI interface (INTF_DSI type): */
|
||||
MDP5_INTF_DSI_MODE_VIDEO,
|
||||
MDP5_INTF_DSI_MODE_COMMAND,
|
||||
|
||||
/* Modes used for WB interface (INTF_WB type): */
|
||||
MDP5_INTF_WB_MODE_BLOCK,
|
||||
MDP5_INTF_WB_MODE_LINE,
|
||||
};
|
||||
|
||||
struct mdp5_interface {
|
||||
int num; /* display interface number */
|
||||
enum mdp5_intf_type type;
|
||||
enum mdp5_intf_mode mode;
|
||||
};
|
||||
|
||||
static inline void mdp5_write(struct mdp5_kms *mdp5_kms, u32 reg, u32 data)
|
||||
{
|
||||
msm_writel(data, mdp5_kms->mmio + reg);
|
||||
|
@ -130,9 +148,9 @@ static inline int pipe2nclients(enum mdp5_pipe pipe)
|
|||
}
|
||||
}
|
||||
|
||||
static inline uint32_t intf2err(int intf)
|
||||
static inline uint32_t intf2err(int intf_num)
|
||||
{
|
||||
switch (intf) {
|
||||
switch (intf_num) {
|
||||
case 0: return MDP5_IRQ_INTF0_UNDER_RUN;
|
||||
case 1: return MDP5_IRQ_INTF1_UNDER_RUN;
|
||||
case 2: return MDP5_IRQ_INTF2_UNDER_RUN;
|
||||
|
@ -141,9 +159,23 @@ static inline uint32_t intf2err(int intf)
|
|||
}
|
||||
}
|
||||
|
||||
static inline uint32_t intf2vblank(int intf)
|
||||
#define GET_PING_PONG_ID(layer_mixer) ((layer_mixer == 5) ? 3 : layer_mixer)
|
||||
static inline uint32_t intf2vblank(int lm, struct mdp5_interface *intf)
|
||||
{
|
||||
switch (intf) {
|
||||
/*
|
||||
* In case of DSI Command Mode, the Ping Pong's read pointer IRQ
|
||||
* acts as a Vblank signal. The Ping Pong buffer used is bound to
|
||||
* layer mixer.
|
||||
*/
|
||||
|
||||
if ((intf->type == INTF_DSI) &&
|
||||
(intf->mode == MDP5_INTF_DSI_MODE_COMMAND))
|
||||
return MDP5_IRQ_PING_PONG_0_RD_PTR << GET_PING_PONG_ID(lm);
|
||||
|
||||
if (intf->type == INTF_WB)
|
||||
return MDP5_IRQ_WB_2_DONE;
|
||||
|
||||
switch (intf->num) {
|
||||
case 0: return MDP5_IRQ_INTF0_VSYNC;
|
||||
case 1: return MDP5_IRQ_INTF1_VSYNC;
|
||||
case 2: return MDP5_IRQ_INTF2_VSYNC;
|
||||
|
@ -152,6 +184,11 @@ static inline uint32_t intf2vblank(int intf)
|
|||
}
|
||||
}
|
||||
|
||||
static inline uint32_t lm2ppdone(int lm)
|
||||
{
|
||||
return MDP5_IRQ_PING_PONG_0_DONE << GET_PING_PONG_ID(lm);
|
||||
}
|
||||
|
||||
int mdp5_disable(struct mdp5_kms *mdp5_kms);
|
||||
int mdp5_enable(struct mdp5_kms *mdp5_kms);
|
||||
|
||||
|
@ -197,13 +234,33 @@ struct drm_plane *mdp5_plane_init(struct drm_device *dev,
|
|||
uint32_t mdp5_crtc_vblank(struct drm_crtc *crtc);
|
||||
|
||||
int mdp5_crtc_get_lm(struct drm_crtc *crtc);
|
||||
struct mdp5_ctl *mdp5_crtc_get_ctl(struct drm_crtc *crtc);
|
||||
void mdp5_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file);
|
||||
void mdp5_crtc_set_intf(struct drm_crtc *crtc, int intf,
|
||||
enum mdp5_intf intf_id);
|
||||
void mdp5_crtc_set_intf(struct drm_crtc *crtc, struct mdp5_interface *intf);
|
||||
struct drm_crtc *mdp5_crtc_init(struct drm_device *dev,
|
||||
struct drm_plane *plane, int id);
|
||||
|
||||
struct drm_encoder *mdp5_encoder_init(struct drm_device *dev, int intf,
|
||||
enum mdp5_intf intf_id);
|
||||
struct drm_encoder *mdp5_encoder_init(struct drm_device *dev,
|
||||
struct mdp5_interface *intf);
|
||||
int mdp5_encoder_set_split_display(struct drm_encoder *encoder,
|
||||
struct drm_encoder *slave_encoder);
|
||||
|
||||
#ifdef CONFIG_DRM_MSM_DSI
|
||||
struct drm_encoder *mdp5_cmd_encoder_init(struct drm_device *dev,
|
||||
struct mdp5_interface *intf);
|
||||
int mdp5_cmd_encoder_set_split_display(struct drm_encoder *encoder,
|
||||
struct drm_encoder *slave_encoder);
|
||||
#else
|
||||
static inline struct drm_encoder *mdp5_cmd_encoder_init(
|
||||
struct drm_device *dev, struct mdp5_interface *intf)
|
||||
{
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
static inline int mdp5_cmd_encoder_set_split_display(
|
||||
struct drm_encoder *encoder, struct drm_encoder *slave_encoder)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __MDP5_KMS_H__ */
|
||||
|
|
|
@ -507,8 +507,8 @@ static int mdp5_plane_mode_set(struct drm_plane *plane,
|
|||
spin_lock_irqsave(&mdp5_plane->pipe_lock, flags);
|
||||
|
||||
mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_IMG_SIZE(pipe),
|
||||
MDP5_PIPE_SRC_IMG_SIZE_WIDTH(src_w) |
|
||||
MDP5_PIPE_SRC_IMG_SIZE_HEIGHT(src_h));
|
||||
MDP5_PIPE_SRC_IMG_SIZE_WIDTH(fb->width) |
|
||||
MDP5_PIPE_SRC_IMG_SIZE_HEIGHT(fb->height));
|
||||
|
||||
mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_SIZE(pipe),
|
||||
MDP5_PIPE_SRC_SIZE_WIDTH(src_w) |
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
* set.
|
||||
*
|
||||
* 2) mdp5_smp_configure():
|
||||
* As hw is programmed, before FLUSH, MDP5_SMP_ALLOC registers
|
||||
* As hw is programmed, before FLUSH, MDP5_MDP_SMP_ALLOC registers
|
||||
* are configured for the union(pending, inuse)
|
||||
*
|
||||
* 3) mdp5_smp_commit():
|
||||
|
@ -74,7 +74,7 @@ struct mdp5_smp {
|
|||
spinlock_t state_lock;
|
||||
mdp5_smp_state_t state; /* to track smp allocation amongst pipes: */
|
||||
|
||||
struct mdp5_client_smp_state client_state[CID_MAX];
|
||||
struct mdp5_client_smp_state client_state[MAX_CLIENTS];
|
||||
};
|
||||
|
||||
static inline
|
||||
|
@ -85,27 +85,31 @@ struct mdp5_kms *get_kms(struct mdp5_smp *smp)
|
|||
return to_mdp5_kms(to_mdp_kms(priv->kms));
|
||||
}
|
||||
|
||||
static inline enum mdp5_client_id pipe2client(enum mdp5_pipe pipe, int plane)
|
||||
static inline u32 pipe2client(enum mdp5_pipe pipe, int plane)
|
||||
{
|
||||
WARN_ON(plane >= pipe2nclients(pipe));
|
||||
switch (pipe) {
|
||||
case SSPP_VIG0: return CID_VIG0_Y + plane;
|
||||
case SSPP_VIG1: return CID_VIG1_Y + plane;
|
||||
case SSPP_VIG2: return CID_VIG2_Y + plane;
|
||||
case SSPP_RGB0: return CID_RGB0;
|
||||
case SSPP_RGB1: return CID_RGB1;
|
||||
case SSPP_RGB2: return CID_RGB2;
|
||||
case SSPP_DMA0: return CID_DMA0_Y + plane;
|
||||
case SSPP_DMA1: return CID_DMA1_Y + plane;
|
||||
case SSPP_VIG3: return CID_VIG3_Y + plane;
|
||||
case SSPP_RGB3: return CID_RGB3;
|
||||
default: return CID_UNUSED;
|
||||
}
|
||||
#define CID_UNUSED 0
|
||||
|
||||
if (WARN_ON(plane >= pipe2nclients(pipe)))
|
||||
return CID_UNUSED;
|
||||
|
||||
/*
|
||||
* Note on SMP clients:
|
||||
* For ViG pipes, fetch Y/Cr/Cb-components clients are always
|
||||
* consecutive, and in that order.
|
||||
*
|
||||
* e.g.:
|
||||
* if mdp5_cfg->smp.clients[SSPP_VIG0] = N,
|
||||
* Y plane's client ID is N
|
||||
* Cr plane's client ID is N + 1
|
||||
* Cb plane's client ID is N + 2
|
||||
*/
|
||||
|
||||
return mdp5_cfg->smp.clients[pipe] + plane;
|
||||
}
|
||||
|
||||
/* step #1: update # of blocks pending for the client: */
|
||||
static int smp_request_block(struct mdp5_smp *smp,
|
||||
enum mdp5_client_id cid, int nblks)
|
||||
u32 cid, int nblks)
|
||||
{
|
||||
struct mdp5_kms *mdp5_kms = get_kms(smp);
|
||||
const struct mdp5_cfg_hw *hw_cfg;
|
||||
|
@ -227,7 +231,7 @@ void mdp5_smp_release(struct mdp5_smp *smp, enum mdp5_pipe pipe)
|
|||
}
|
||||
|
||||
static void update_smp_state(struct mdp5_smp *smp,
|
||||
enum mdp5_client_id cid, mdp5_smp_state_t *assigned)
|
||||
u32 cid, mdp5_smp_state_t *assigned)
|
||||
{
|
||||
struct mdp5_kms *mdp5_kms = get_kms(smp);
|
||||
int cnt = smp->blk_cnt;
|
||||
|
@ -237,25 +241,25 @@ static void update_smp_state(struct mdp5_smp *smp,
|
|||
int idx = blk / 3;
|
||||
int fld = blk % 3;
|
||||
|
||||
val = mdp5_read(mdp5_kms, REG_MDP5_SMP_ALLOC_W_REG(idx));
|
||||
val = mdp5_read(mdp5_kms, REG_MDP5_MDP_SMP_ALLOC_W_REG(0, idx));
|
||||
|
||||
switch (fld) {
|
||||
case 0:
|
||||
val &= ~MDP5_SMP_ALLOC_W_REG_CLIENT0__MASK;
|
||||
val |= MDP5_SMP_ALLOC_W_REG_CLIENT0(cid);
|
||||
val &= ~MDP5_MDP_SMP_ALLOC_W_REG_CLIENT0__MASK;
|
||||
val |= MDP5_MDP_SMP_ALLOC_W_REG_CLIENT0(cid);
|
||||
break;
|
||||
case 1:
|
||||
val &= ~MDP5_SMP_ALLOC_W_REG_CLIENT1__MASK;
|
||||
val |= MDP5_SMP_ALLOC_W_REG_CLIENT1(cid);
|
||||
val &= ~MDP5_MDP_SMP_ALLOC_W_REG_CLIENT1__MASK;
|
||||
val |= MDP5_MDP_SMP_ALLOC_W_REG_CLIENT1(cid);
|
||||
break;
|
||||
case 2:
|
||||
val &= ~MDP5_SMP_ALLOC_W_REG_CLIENT2__MASK;
|
||||
val |= MDP5_SMP_ALLOC_W_REG_CLIENT2(cid);
|
||||
val &= ~MDP5_MDP_SMP_ALLOC_W_REG_CLIENT2__MASK;
|
||||
val |= MDP5_MDP_SMP_ALLOC_W_REG_CLIENT2(cid);
|
||||
break;
|
||||
}
|
||||
|
||||
mdp5_write(mdp5_kms, REG_MDP5_SMP_ALLOC_W_REG(idx), val);
|
||||
mdp5_write(mdp5_kms, REG_MDP5_SMP_ALLOC_R_REG(idx), val);
|
||||
mdp5_write(mdp5_kms, REG_MDP5_MDP_SMP_ALLOC_W_REG(0, idx), val);
|
||||
mdp5_write(mdp5_kms, REG_MDP5_MDP_SMP_ALLOC_R_REG(0, idx), val);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -267,7 +271,7 @@ void mdp5_smp_configure(struct mdp5_smp *smp, enum mdp5_pipe pipe)
|
|||
int i;
|
||||
|
||||
for (i = 0; i < pipe2nclients(pipe); i++) {
|
||||
enum mdp5_client_id cid = pipe2client(pipe, i);
|
||||
u32 cid = pipe2client(pipe, i);
|
||||
struct mdp5_client_smp_state *ps = &smp->client_state[cid];
|
||||
|
||||
bitmap_or(assigned, ps->inuse, ps->pending, cnt);
|
||||
|
@ -283,7 +287,7 @@ void mdp5_smp_commit(struct mdp5_smp *smp, enum mdp5_pipe pipe)
|
|||
int i;
|
||||
|
||||
for (i = 0; i < pipe2nclients(pipe); i++) {
|
||||
enum mdp5_client_id cid = pipe2client(pipe, i);
|
||||
u32 cid = pipe2client(pipe, i);
|
||||
struct mdp5_client_smp_state *ps = &smp->client_state[cid];
|
||||
|
||||
/*
|
||||
|
|
|
@ -182,6 +182,83 @@ static int get_mdp_ver(struct platform_device *pdev)
|
|||
return 4;
|
||||
}
|
||||
|
||||
#include <linux/of_address.h>
|
||||
|
||||
static int msm_init_vram(struct drm_device *dev)
|
||||
{
|
||||
struct msm_drm_private *priv = dev->dev_private;
|
||||
unsigned long size = 0;
|
||||
int ret = 0;
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
/* In the device-tree world, we could have a 'memory-region'
|
||||
* phandle, which gives us a link to our "vram". Allocating
|
||||
* is all nicely abstracted behind the dma api, but we need
|
||||
* to know the entire size to allocate it all in one go. There
|
||||
* are two cases:
|
||||
* 1) device with no IOMMU, in which case we need exclusive
|
||||
* access to a VRAM carveout big enough for all gpu
|
||||
* buffers
|
||||
* 2) device with IOMMU, but where the bootloader puts up
|
||||
* a splash screen. In this case, the VRAM carveout
|
||||
* need only be large enough for fbdev fb. But we need
|
||||
* exclusive access to the buffer to avoid the kernel
|
||||
* using those pages for other purposes (which appears
|
||||
* as corruption on screen before we have a chance to
|
||||
* load and do initial modeset)
|
||||
*/
|
||||
struct device_node *node;
|
||||
|
||||
node = of_parse_phandle(dev->dev->of_node, "memory-region", 0);
|
||||
if (node) {
|
||||
struct resource r;
|
||||
ret = of_address_to_resource(node, 0, &r);
|
||||
if (ret)
|
||||
return ret;
|
||||
size = r.end - r.start;
|
||||
DRM_INFO("using VRAM carveout: %lx@%08x\n", size, r.start);
|
||||
} else
|
||||
#endif
|
||||
|
||||
/* if we have no IOMMU, then we need to use carveout allocator.
|
||||
* Grab the entire CMA chunk carved out in early startup in
|
||||
* mach-msm:
|
||||
*/
|
||||
if (!iommu_present(&platform_bus_type)) {
|
||||
DRM_INFO("using %s VRAM carveout\n", vram);
|
||||
size = memparse(vram, NULL);
|
||||
}
|
||||
|
||||
if (size) {
|
||||
DEFINE_DMA_ATTRS(attrs);
|
||||
void *p;
|
||||
|
||||
priv->vram.size = size;
|
||||
|
||||
drm_mm_init(&priv->vram.mm, 0, (size >> PAGE_SHIFT) - 1);
|
||||
|
||||
dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &attrs);
|
||||
dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
|
||||
|
||||
/* note that for no-kernel-mapping, the vaddr returned
|
||||
* is bogus, but non-null if allocation succeeded:
|
||||
*/
|
||||
p = dma_alloc_attrs(dev->dev, size,
|
||||
&priv->vram.paddr, GFP_KERNEL, &attrs);
|
||||
if (!p) {
|
||||
dev_err(dev->dev, "failed to allocate VRAM\n");
|
||||
priv->vram.paddr = 0;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dev_info(dev->dev, "VRAM: %08x->%08x\n",
|
||||
(uint32_t)priv->vram.paddr,
|
||||
(uint32_t)(priv->vram.paddr + size));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int msm_load(struct drm_device *dev, unsigned long flags)
|
||||
{
|
||||
struct platform_device *pdev = dev->platformdev;
|
||||
|
@ -206,40 +283,9 @@ static int msm_load(struct drm_device *dev, unsigned long flags)
|
|||
|
||||
drm_mode_config_init(dev);
|
||||
|
||||
/* if we have no IOMMU, then we need to use carveout allocator.
|
||||
* Grab the entire CMA chunk carved out in early startup in
|
||||
* mach-msm:
|
||||
*/
|
||||
if (!iommu_present(&platform_bus_type)) {
|
||||
DEFINE_DMA_ATTRS(attrs);
|
||||
unsigned long size;
|
||||
void *p;
|
||||
|
||||
DBG("using %s VRAM carveout", vram);
|
||||
size = memparse(vram, NULL);
|
||||
priv->vram.size = size;
|
||||
|
||||
drm_mm_init(&priv->vram.mm, 0, (size >> PAGE_SHIFT) - 1);
|
||||
|
||||
dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &attrs);
|
||||
dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
|
||||
|
||||
/* note that for no-kernel-mapping, the vaddr returned
|
||||
* is bogus, but non-null if allocation succeeded:
|
||||
*/
|
||||
p = dma_alloc_attrs(dev->dev, size,
|
||||
&priv->vram.paddr, GFP_KERNEL, &attrs);
|
||||
if (!p) {
|
||||
dev_err(dev->dev, "failed to allocate VRAM\n");
|
||||
priv->vram.paddr = 0;
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
dev_info(dev->dev, "VRAM: %08x->%08x\n",
|
||||
(uint32_t)priv->vram.paddr,
|
||||
(uint32_t)(priv->vram.paddr + size));
|
||||
}
|
||||
ret = msm_init_vram(dev);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
platform_set_drvdata(pdev, dev);
|
||||
|
||||
|
@ -1030,6 +1076,7 @@ static struct platform_driver msm_platform_driver = {
|
|||
static int __init msm_drm_register(void)
|
||||
{
|
||||
DBG("init");
|
||||
msm_dsi_register();
|
||||
msm_edp_register();
|
||||
hdmi_register();
|
||||
adreno_register();
|
||||
|
@ -1043,6 +1090,7 @@ static void __exit msm_drm_unregister(void)
|
|||
hdmi_unregister();
|
||||
adreno_unregister();
|
||||
msm_edp_unregister();
|
||||
msm_dsi_unregister();
|
||||
}
|
||||
|
||||
module_init(msm_drm_register);
|
||||
|
|
|
@ -82,6 +82,9 @@ struct msm_drm_private {
|
|||
*/
|
||||
struct msm_edp *edp;
|
||||
|
||||
/* DSI is shared by mdp4 and mdp5 */
|
||||
struct msm_dsi *dsi[2];
|
||||
|
||||
/* when we have more than one 'msm_gpu' these need to be an array: */
|
||||
struct msm_gpu *gpu;
|
||||
struct msm_file_private *lastctx;
|
||||
|
@ -236,6 +239,32 @@ void __exit msm_edp_unregister(void);
|
|||
int msm_edp_modeset_init(struct msm_edp *edp, struct drm_device *dev,
|
||||
struct drm_encoder *encoder);
|
||||
|
||||
struct msm_dsi;
|
||||
enum msm_dsi_encoder_id {
|
||||
MSM_DSI_VIDEO_ENCODER_ID = 0,
|
||||
MSM_DSI_CMD_ENCODER_ID = 1,
|
||||
MSM_DSI_ENCODER_NUM = 2
|
||||
};
|
||||
#ifdef CONFIG_DRM_MSM_DSI
|
||||
void __init msm_dsi_register(void);
|
||||
void __exit msm_dsi_unregister(void);
|
||||
int msm_dsi_modeset_init(struct msm_dsi *msm_dsi, struct drm_device *dev,
|
||||
struct drm_encoder *encoders[MSM_DSI_ENCODER_NUM]);
|
||||
#else
|
||||
static inline void __init msm_dsi_register(void)
|
||||
{
|
||||
}
|
||||
static inline void __exit msm_dsi_unregister(void)
|
||||
{
|
||||
}
|
||||
static inline int msm_dsi_modeset_init(struct msm_dsi *msm_dsi,
|
||||
struct drm_device *dev,
|
||||
struct drm_encoder *encoders[MSM_DSI_ENCODER_NUM])
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m);
|
||||
void msm_gem_describe_objects(struct list_head *list, struct seq_file *m);
|
||||
|
|
|
@ -110,7 +110,8 @@ static int msm_fbdev_create(struct drm_fb_helper *helper,
|
|||
size = mode_cmd.pitches[0] * mode_cmd.height;
|
||||
DBG("allocating %d bytes for fb %d", size, dev->primary->index);
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
fbdev->bo = msm_gem_new(dev, size, MSM_BO_SCANOUT | MSM_BO_WC);
|
||||
fbdev->bo = msm_gem_new(dev, size, MSM_BO_SCANOUT |
|
||||
MSM_BO_WC | MSM_BO_STOLEN);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
if (IS_ERR(fbdev->bo)) {
|
||||
ret = PTR_ERR(fbdev->bo);
|
||||
|
|
|
@ -32,6 +32,12 @@ static dma_addr_t physaddr(struct drm_gem_object *obj)
|
|||
priv->vram.paddr;
|
||||
}
|
||||
|
||||
static bool use_pages(struct drm_gem_object *obj)
|
||||
{
|
||||
struct msm_gem_object *msm_obj = to_msm_bo(obj);
|
||||
return !msm_obj->vram_node;
|
||||
}
|
||||
|
||||
/* allocate pages from VRAM carveout, used when no IOMMU: */
|
||||
static struct page **get_pages_vram(struct drm_gem_object *obj,
|
||||
int npages)
|
||||
|
@ -72,7 +78,7 @@ static struct page **get_pages(struct drm_gem_object *obj)
|
|||
struct page **p;
|
||||
int npages = obj->size >> PAGE_SHIFT;
|
||||
|
||||
if (iommu_present(&platform_bus_type))
|
||||
if (use_pages(obj))
|
||||
p = drm_gem_get_pages(obj);
|
||||
else
|
||||
p = get_pages_vram(obj, npages);
|
||||
|
@ -116,7 +122,7 @@ static void put_pages(struct drm_gem_object *obj)
|
|||
sg_free_table(msm_obj->sgt);
|
||||
kfree(msm_obj->sgt);
|
||||
|
||||
if (iommu_present(&platform_bus_type))
|
||||
if (use_pages(obj))
|
||||
drm_gem_put_pages(obj, msm_obj->pages, true, false);
|
||||
else {
|
||||
drm_mm_remove_node(msm_obj->vram_node);
|
||||
|
@ -580,6 +586,7 @@ static int msm_gem_new_impl(struct drm_device *dev,
|
|||
struct msm_drm_private *priv = dev->dev_private;
|
||||
struct msm_gem_object *msm_obj;
|
||||
unsigned sz;
|
||||
bool use_vram = false;
|
||||
|
||||
switch (flags & MSM_BO_CACHE_MASK) {
|
||||
case MSM_BO_UNCACHED:
|
||||
|
@ -592,15 +599,23 @@ static int msm_gem_new_impl(struct drm_device *dev,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
sz = sizeof(*msm_obj);
|
||||
if (!iommu_present(&platform_bus_type))
|
||||
use_vram = true;
|
||||
else if ((flags & MSM_BO_STOLEN) && priv->vram.size)
|
||||
use_vram = true;
|
||||
|
||||
if (WARN_ON(use_vram && !priv->vram.size))
|
||||
return -EINVAL;
|
||||
|
||||
sz = sizeof(*msm_obj);
|
||||
if (use_vram)
|
||||
sz += sizeof(struct drm_mm_node);
|
||||
|
||||
msm_obj = kzalloc(sz, GFP_KERNEL);
|
||||
if (!msm_obj)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!iommu_present(&platform_bus_type))
|
||||
if (use_vram)
|
||||
msm_obj->vram_node = (void *)&msm_obj[1];
|
||||
|
||||
msm_obj->flags = flags;
|
||||
|
@ -630,7 +645,7 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev,
|
|||
if (ret)
|
||||
goto fail;
|
||||
|
||||
if (iommu_present(&platform_bus_type)) {
|
||||
if (use_pages(obj)) {
|
||||
ret = drm_gem_object_init(dev, obj, size);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
#include <linux/reservation.h>
|
||||
#include "msm_drv.h"
|
||||
|
||||
/* Additional internal-use only BO flags: */
|
||||
#define MSM_BO_STOLEN 0x10000000 /* try to use stolen/splash memory */
|
||||
|
||||
struct msm_gem_object {
|
||||
struct drm_gem_object base;
|
||||
|
||||
|
@ -59,7 +62,7 @@ struct msm_gem_object {
|
|||
struct reservation_object _resv;
|
||||
|
||||
/* For physically contiguous buffers. Used when we don't have
|
||||
* an IOMMU.
|
||||
* an IOMMU. Also used for stolen/splashscreen buffer.
|
||||
*/
|
||||
struct drm_mm_node *vram_node;
|
||||
};
|
||||
|
|
|
@ -47,6 +47,10 @@ struct msm_kms_funcs {
|
|||
const struct msm_format *(*get_format)(struct msm_kms *kms, uint32_t format);
|
||||
long (*round_pixclk)(struct msm_kms *kms, unsigned long rate,
|
||||
struct drm_encoder *encoder);
|
||||
int (*set_split_display)(struct msm_kms *kms,
|
||||
struct drm_encoder *encoder,
|
||||
struct drm_encoder *slave_encoder,
|
||||
bool is_cmd_mode);
|
||||
/* cleanup: */
|
||||
void (*preclose)(struct msm_kms *kms, struct drm_file *file);
|
||||
void (*destroy)(struct msm_kms *kms);
|
||||
|
|
Loading…
Reference in New Issue