Commit e2b80bac authored by Dave Airlie's avatar Dave Airlie

Merge branch 'upstream/analogix-dp-20160705' of git://github.com/yakir-Yang/linux into drm-next

Please consider merging this tag, which contains the v4 misc fixes and add RK3399 eDP support patches[0] I sent on 2016-06-29, rebased onto v4.7-rc5.

* 'upstream/analogix-dp-20160705' of git://github.com/yakir-Yang/linux:
  dt-bindings: analogix_dp: rockchip: correct the wrong compatible name
  drm/rockchip: analogix_dp: introduce the pclk for grf
  drm/bridge: analogix_dp: fix no drm hpd event when panel plug in
  drm/rockchip: analogix_dp: update the comments about why need to hardcode VOP output mode
  drm/rockchip: analogix_dp: correct the connector display color format and bpc
  drm/bridge: analogix_dp: passing the connector as an argument in .get_modes()
  drm/rockchip: analogix_dp: make panel detect to an optional action
  drm/rockchip: analogix_dp: add rk3399 eDP support
  drm/bridge: analogix_dp: some rockchip chips need to flip REF_CLK bit setting
  drm/bridge: analogix_dp: correct the register bit define error in ANALOGIX_DP_PLL_REG_1
  drm/rockchip: analogix_dp: split the lcdc select setting into device data
parents d3c35337 77b8d755
......@@ -5,6 +5,7 @@ Required properties for dp-controller:
platform specific such as:
* "samsung,exynos5-dp"
* "rockchip,rk3288-dp"
* "rockchip,rk3399-edp"
-reg:
physical base address of the controller and length
of memory mapped region.
......
......@@ -2,7 +2,8 @@ Rockchip RK3288 specific extensions to the Analogix Display Port
================================
Required properties:
- compatible: "rockchip,rk3288-edp";
- compatible: "rockchip,rk3288-dp",
"rockchip,rk3399-edp";
- reg: physical base address of the controller and length
......@@ -27,6 +28,12 @@ Required properties:
Port 0: contained 2 endpoints, connecting to the output of vop.
Port 1: contained 1 endpoint, connecting to the input of panel.
Optional property for different chips:
- clocks: from common clock binding: handle to grf_vio clock.
- clock-names: from common clock binding:
Required elements: "grf"
For the below properties, please refer to Analogix DP binding document:
* Documentation/devicetree/bindings/drm/bridge/analogix_dp.txt
- phys (required)
......
......@@ -938,7 +938,7 @@ int analogix_dp_get_modes(struct drm_connector *connector)
num_modes += drm_panel_get_modes(dp->plat_data->panel);
if (dp->plat_data->get_modes)
num_modes += dp->plat_data->get_modes(dp->plat_data);
num_modes += dp->plat_data->get_modes(dp->plat_data, connector);
return num_modes;
}
......@@ -1208,6 +1208,7 @@ static int analogix_dp_dt_parse_pdata(struct analogix_dp_device *dp)
switch (dp->plat_data->dev_type) {
case RK3288_DP:
case RK3399_EDP:
/*
* Like Rk3288 DisplayPort TRM indicate that "Main link
* containing 4 physical lanes of 2.7/1.62 Gbps/lane".
......
......@@ -127,10 +127,10 @@ enum analog_power_block {
};
enum dp_irq_type {
DP_IRQ_TYPE_HP_CABLE_IN,
DP_IRQ_TYPE_HP_CABLE_OUT,
DP_IRQ_TYPE_HP_CHANGE,
DP_IRQ_TYPE_UNKNOWN,
DP_IRQ_TYPE_HP_CABLE_IN = BIT(0),
DP_IRQ_TYPE_HP_CABLE_OUT = BIT(1),
DP_IRQ_TYPE_HP_CHANGE = BIT(2),
DP_IRQ_TYPE_UNKNOWN = BIT(3),
};
struct video_info {
......
......@@ -74,8 +74,12 @@ void analogix_dp_init_analog_param(struct analogix_dp_device *dp)
reg = SEL_24M | TX_DVDD_BIT_1_0625V;
writel(reg, dp->reg_base + ANALOGIX_DP_ANALOG_CTL_2);
if (dp->plat_data && (dp->plat_data->dev_type == RK3288_DP)) {
writel(REF_CLK_24M, dp->reg_base + ANALOGIX_DP_PLL_REG_1);
if (dp->plat_data && is_rockchip(dp->plat_data->dev_type)) {
reg = REF_CLK_24M;
if (dp->plat_data->dev_type == RK3288_DP)
reg ^= REF_CLK_MASK;
writel(reg, dp->reg_base + ANALOGIX_DP_PLL_REG_1);
writel(0x95, dp->reg_base + ANALOGIX_DP_PLL_REG_2);
writel(0x40, dp->reg_base + ANALOGIX_DP_PLL_REG_3);
writel(0x58, dp->reg_base + ANALOGIX_DP_PLL_REG_4);
......@@ -244,7 +248,7 @@ void analogix_dp_set_analog_power_down(struct analogix_dp_device *dp,
u32 reg;
u32 phy_pd_addr = ANALOGIX_DP_PHY_PD;
if (dp->plat_data && (dp->plat_data->dev_type == RK3288_DP))
if (dp->plat_data && is_rockchip(dp->plat_data->dev_type))
phy_pd_addr = ANALOGIX_DP_PD;
switch (block) {
......@@ -448,7 +452,7 @@ void analogix_dp_init_aux(struct analogix_dp_device *dp)
analogix_dp_reset_aux(dp);
/* Disable AUX transaction H/W retry */
if (dp->plat_data && (dp->plat_data->dev_type == RK3288_DP))
if (dp->plat_data && is_rockchip(dp->plat_data->dev_type))
reg = AUX_BIT_PERIOD_EXPECTED_DELAY(0) |
AUX_HW_RETRY_COUNT_SEL(3) |
AUX_HW_RETRY_INTERVAL_600_MICROSECONDS;
......
......@@ -163,8 +163,9 @@
#define HSYNC_POLARITY_CFG (0x1 << 0)
/* ANALOGIX_DP_PLL_REG_1 */
#define REF_CLK_24M (0x1 << 1)
#define REF_CLK_27M (0x0 << 1)
#define REF_CLK_24M (0x1 << 0)
#define REF_CLK_27M (0x0 << 0)
#define REF_CLK_MASK (0x1 << 0)
/* ANALOGIX_DP_LANE_MAP */
#define LANE3_MAP_LOGIC_LANE_0 (0x0 << 6)
......
......@@ -67,10 +67,10 @@ static int exynos_dp_poweroff(struct analogix_dp_plat_data *plat_data)
return exynos_dp_crtc_clock_enable(plat_data, false);
}
static int exynos_dp_get_modes(struct analogix_dp_plat_data *plat_data)
static int exynos_dp_get_modes(struct analogix_dp_plat_data *plat_data,
struct drm_connector *connector)
{
struct exynos_dp_device *dp = to_dp(plat_data);
struct drm_connector *connector = dp->connector;
struct drm_display_mode *mode;
int num_modes = 0;
......
......@@ -14,6 +14,7 @@
#include <linux/component.h>
#include <linux/mfd/syscon.h>
#include <linux/of_device.h>
#include <linux/of_graph.h>
#include <linux/regmap.h>
#include <linux/reset.h>
......@@ -33,13 +34,28 @@
#include "rockchip_drm_drv.h"
#include "rockchip_drm_vop.h"
#define RK3288_GRF_SOC_CON6 0x25c
#define RK3288_EDP_LCDC_SEL BIT(5)
#define RK3399_GRF_SOC_CON20 0x6250
#define RK3399_EDP_LCDC_SEL BIT(5)
#define HIWORD_UPDATE(val, mask) (val | (mask) << 16)
#define to_dp(nm) container_of(nm, struct rockchip_dp_device, nm)
/* dp grf register offset */
#define GRF_SOC_CON6 0x025c
#define GRF_EDP_LCD_SEL_MASK BIT(5)
#define GRF_EDP_SEL_VOP_LIT BIT(5)
#define GRF_EDP_SEL_VOP_BIG 0
/**
* struct rockchip_dp_chip_data - splite the grf setting of kind of chips
* @lcdsel_grf_reg: grf register offset of lcdc select
* @lcdsel_big: reg value of selecting vop big for eDP
* @lcdsel_lit: reg value of selecting vop little for eDP
* @chip_type: specific chip type
*/
struct rockchip_dp_chip_data {
u32 lcdsel_grf_reg;
u32 lcdsel_big;
u32 lcdsel_lit;
u32 chip_type;
};
struct rockchip_dp_device {
struct drm_device *drm_dev;
......@@ -48,9 +64,12 @@ struct rockchip_dp_device {
struct drm_display_mode mode;
struct clk *pclk;
struct clk *grfclk;
struct regmap *grf;
struct reset_control *rst;
const struct rockchip_dp_chip_data *data;
struct analogix_dp_plat_data plat_data;
};
......@@ -92,6 +111,23 @@ static int rockchip_dp_powerdown(struct analogix_dp_plat_data *plat_data)
return 0;
}
static int rockchip_dp_get_modes(struct analogix_dp_plat_data *plat_data,
struct drm_connector *connector)
{
struct drm_display_info *di = &connector->display_info;
/* VOP couldn't output YUV video format for eDP rightly */
u32 mask = DRM_COLOR_FORMAT_YCRCB444 | DRM_COLOR_FORMAT_YCRCB422;
if ((di->color_formats & mask)) {
DRM_DEBUG_KMS("Swapping display color format from YUV to RGB\n");
di->color_formats &= ~mask;
di->color_formats |= DRM_COLOR_FORMAT_RGB444;
di->bpc = 8;
}
return 0;
}
static bool
rockchip_dp_drm_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
......@@ -119,17 +155,23 @@ static void rockchip_dp_drm_encoder_enable(struct drm_encoder *encoder)
return;
if (ret)
val = GRF_EDP_SEL_VOP_LIT | (GRF_EDP_LCD_SEL_MASK << 16);
val = dp->data->lcdsel_lit;
else
val = GRF_EDP_SEL_VOP_BIG | (GRF_EDP_LCD_SEL_MASK << 16);
val = dp->data->lcdsel_big;
dev_dbg(dp->dev, "vop %s output to dp\n", (ret) ? "LIT" : "BIG");
ret = regmap_write(dp->grf, GRF_SOC_CON6, val);
if (ret != 0) {
dev_err(dp->dev, "Could not write to GRF: %d\n", ret);
ret = clk_prepare_enable(dp->grfclk);
if (ret < 0) {
dev_err(dp->dev, "failed to enable grfclk %d\n", ret);
return;
}
ret = regmap_write(dp->grf, dp->data->lcdsel_grf_reg, val);
if (ret != 0)
dev_err(dp->dev, "Could not write to GRF: %d\n", ret);
clk_disable_unprepare(dp->grfclk);
}
static void rockchip_dp_drm_encoder_nop(struct drm_encoder *encoder)
......@@ -143,22 +185,29 @@ rockchip_dp_drm_encoder_atomic_check(struct drm_encoder *encoder,
struct drm_connector_state *conn_state)
{
struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
struct rockchip_dp_device *dp = to_dp(encoder);
int ret;
/*
* FIXME(Yakir): driver should configure the CRTC output video
* mode with the display information which indicated the monitor
* support colorimetry.
*
* But don't know why the CRTC driver seems could only output the
* RGBaaa rightly. For example, if connect the "innolux,n116bge"
* eDP screen, EDID would indicated that screen only accepted the
* 6bpc mode. But if I configure CRTC to RGB666 output, then eDP
* screen would show a blue picture (RGB888 show a green picture).
* But if I configure CTRC to RGBaaa, and eDP driver still keep
* RGB666 input video mode, then screen would works prefect.
* The hardware IC designed that VOP must output the RGB10 video
* format to eDP controller, and if eDP panel only support RGB8,
* then eDP controller should cut down the video data, not via VOP
* controller, that's why we need to hardcode the VOP output mode
* to RGA10 here.
*/
s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
s->output_type = DRM_MODE_CONNECTOR_eDP;
if (dp->data->chip_type == RK3399_EDP) {
/*
* For RK3399, VOP Lit must code the out mode to RGB888,
* VOP Big must code the out mode to RGB10.
*/
ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node,
encoder);
if (ret > 0)
s->output_mode = ROCKCHIP_OUT_MODE_P888;
}
return 0;
}
......@@ -192,6 +241,16 @@ static int rockchip_dp_init(struct rockchip_dp_device *dp)
return PTR_ERR(dp->grf);
}
dp->grfclk = devm_clk_get(dev, "grf");
if (PTR_ERR(dp->grfclk) == -ENOENT) {
dp->grfclk = NULL;
} else if (PTR_ERR(dp->grfclk) == -EPROBE_DEFER) {
return -EPROBE_DEFER;
} else if (IS_ERR(dp->grfclk)) {
dev_err(dev, "failed to get grf clock\n");
return PTR_ERR(dp->grfclk);
}
dp->pclk = devm_clk_get(dev, "pclk");
if (IS_ERR(dp->pclk)) {
dev_err(dev, "failed to get pclk property\n");
......@@ -246,6 +305,7 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
void *data)
{
struct rockchip_dp_device *dp = dev_get_drvdata(dev);
const struct rockchip_dp_chip_data *dp_data;
struct drm_device *drm_dev = data;
int ret;
......@@ -256,10 +316,15 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
*/
dev_set_drvdata(dev, NULL);
dp_data = of_device_get_match_data(dev);
if (!dp_data)
return -ENODEV;
ret = rockchip_dp_init(dp);
if (ret < 0)
return ret;
dp->data = dp_data;
dp->drm_dev = drm_dev;
ret = rockchip_dp_drm_create_encoder(dp);
......@@ -270,9 +335,10 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
dp->plat_data.encoder = &dp->encoder;
dp->plat_data.dev_type = RK3288_DP;
dp->plat_data.dev_type = dp->data->chip_type;
dp->plat_data.power_on = rockchip_dp_poweron;
dp->plat_data.power_off = rockchip_dp_powerdown;
dp->plat_data.get_modes = rockchip_dp_get_modes;
return analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
}
......@@ -292,38 +358,33 @@ static int rockchip_dp_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *panel_node, *port, *endpoint;
struct drm_panel *panel = NULL;
struct rockchip_dp_device *dp;
struct drm_panel *panel;
port = of_graph_get_port_by_id(dev->of_node, 1);
if (!port) {
dev_err(dev, "can't find output port\n");
return -EINVAL;
}
endpoint = of_get_child_by_name(port, "endpoint");
of_node_put(port);
if (!endpoint) {
dev_err(dev, "no output endpoint found\n");
return -EINVAL;
}
panel_node = of_graph_get_remote_port_parent(endpoint);
of_node_put(endpoint);
if (!panel_node) {
dev_err(dev, "no output node found\n");
return -EINVAL;
}
panel = of_drm_find_panel(panel_node);
if (!panel) {
DRM_ERROR("failed to find panel\n");
if (port) {
endpoint = of_get_child_by_name(port, "endpoint");
of_node_put(port);
if (!endpoint) {
dev_err(dev, "no output endpoint found\n");
return -EINVAL;
}
panel_node = of_graph_get_remote_port_parent(endpoint);
of_node_put(endpoint);
if (!panel_node) {
dev_err(dev, "no output node found\n");
return -EINVAL;
}
panel = of_drm_find_panel(panel_node);
of_node_put(panel_node);
return -EPROBE_DEFER;
if (!panel) {
DRM_ERROR("failed to find panel\n");
return -EPROBE_DEFER;
}
}
of_node_put(panel_node);
dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL);
if (!dp)
return -ENOMEM;
......@@ -356,8 +417,23 @@ static const struct dev_pm_ops rockchip_dp_pm_ops = {
#endif
};
static const struct rockchip_dp_chip_data rk3399_edp = {
.lcdsel_grf_reg = RK3399_GRF_SOC_CON20,
.lcdsel_big = HIWORD_UPDATE(0, RK3399_EDP_LCDC_SEL),
.lcdsel_lit = HIWORD_UPDATE(RK3399_EDP_LCDC_SEL, RK3399_EDP_LCDC_SEL),
.chip_type = RK3399_EDP,
};
static const struct rockchip_dp_chip_data rk3288_dp = {
.lcdsel_grf_reg = RK3288_GRF_SOC_CON6,
.lcdsel_big = HIWORD_UPDATE(0, RK3288_EDP_LCDC_SEL),
.lcdsel_lit = HIWORD_UPDATE(RK3288_EDP_LCDC_SEL, RK3288_EDP_LCDC_SEL),
.chip_type = RK3288_DP,
};
static const struct of_device_id rockchip_dp_dt_ids[] = {
{.compatible = "rockchip,rk3288-dp",},
{.compatible = "rockchip,rk3288-dp", .data = &rk3288_dp },
{.compatible = "rockchip,rk3399-edp", .data = &rk3399_edp },
{}
};
MODULE_DEVICE_TABLE(of, rockchip_dp_dt_ids);
......
......@@ -16,8 +16,14 @@
enum analogix_dp_devtype {
EXYNOS_DP,
RK3288_DP,
RK3399_EDP,
};
static inline bool is_rockchip(enum analogix_dp_devtype type)
{
return type == RK3288_DP || type == RK3399_EDP;
}
struct analogix_dp_plat_data {
enum analogix_dp_devtype dev_type;
struct drm_panel *panel;
......@@ -28,7 +34,8 @@ struct analogix_dp_plat_data {
int (*power_off)(struct analogix_dp_plat_data *);
int (*attach)(struct analogix_dp_plat_data *, struct drm_bridge *,
struct drm_connector *);
int (*get_modes)(struct analogix_dp_plat_data *);
int (*get_modes)(struct analogix_dp_plat_data *,
struct drm_connector *);
};
int analogix_dp_resume(struct device *dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment