Commit 4526903a authored by Dave Airlie's avatar Dave Airlie

Merge branch 'msm-next' of git://people.freedesktop.org/~robclark/linux into drm-next

Main thing this time around is DSI support for msm8960/apq8064, which
should be helpful for getting an upstream kernel working on
nexus7/nexus4/etc.

* 'msm-next' of git://people.freedesktop.org/~robclark/linux: (29 commits)
  drm/msm/mdp: fix a problematic usage of WARN_ON()
  drm/msm/dsi: Added missing mutex_unlock
  drm/msm: ratelimit error irq msgs
  drm/msm: Use unlocked gem unreferencing
  drm/msm: trivial whitespace fix
  dt-bindings: msm/dsi: Add DSIv2 documentation
  dt-bindings: msm/dsi: Fix the order in which clocks are listed
  drm/msm/dsi: Enable MMSS SPFB port via syscon
  drm/msm/dsi: Don't use iommu for command TX buffer for DSIv2
  drm/msm/dsi: Add dsi_cfg for APQ8064
  drm/msm/dsi: Set up link clocks for DSIv2
  drm/msm/dsi: Parse bus clocks from a list
  drm/msm/dsi: Delay dsi_clk_init
  drm/msm/dsi: Use a better way to figure out DSI version
  drm/msm/dsi: Add DSI PLL for 28nm 8960 PHY
  drm/msm/dsi: Add support for 28nm PHY on 8960
  drm/msm/dsi: Don't get byte/pixel source clocks from DT
  drm/msm/mdp4: Initialize DSI encoders
  drm/msm/mdp4: Call custom round_pixclk helper only if the encoder type is TMDS
  drm/msm/dsi: Add a mdp4 encoder for DSI
  ...
parents 663a233e 2abd1c88
...@@ -14,17 +14,20 @@ Required properties: ...@@ -14,17 +14,20 @@ Required properties:
- clocks: device clocks - clocks: device clocks
See Documentation/devicetree/bindings/clocks/clock-bindings.txt for details. See Documentation/devicetree/bindings/clocks/clock-bindings.txt for details.
- clock-names: the following clocks are required: - clock-names: the following clocks are required:
* "mdp_core_clk"
* "iface_clk"
* "bus_clk" * "bus_clk"
* "byte_clk"
* "core_clk"
* "core_mmss_clk" * "core_mmss_clk"
* "iface_clk" * "byte_clk"
* "mdp_core_clk"
* "pixel_clk" * "pixel_clk"
* "core_clk"
For DSIv2, we need an additional clock:
* "src_clk"
- vdd-supply: phandle to vdd regulator device node - vdd-supply: phandle to vdd regulator device node
- vddio-supply: phandle to vdd-io regulator device node - vddio-supply: phandle to vdd-io regulator device node
- vdda-supply: phandle to vdda regulator device node - vdda-supply: phandle to vdda regulator device node
- qcom,dsi-phy: phandle to DSI PHY device node - qcom,dsi-phy: phandle to DSI PHY device node
- syscon-sfpb: A phandle to mmss_sfpb syscon node (only for DSIv2)
Optional properties: Optional properties:
- panel@0: Node of panel connected to this DSI controller. - panel@0: Node of panel connected to this DSI controller.
...@@ -51,6 +54,7 @@ Required properties: ...@@ -51,6 +54,7 @@ Required properties:
* "qcom,dsi-phy-28nm-hpm" * "qcom,dsi-phy-28nm-hpm"
* "qcom,dsi-phy-28nm-lp" * "qcom,dsi-phy-28nm-lp"
* "qcom,dsi-phy-20nm" * "qcom,dsi-phy-20nm"
* "qcom,dsi-phy-28nm-8960"
- reg: Physical base address and length of the registers of PLL, PHY and PHY - reg: Physical base address and length of the registers of PLL, PHY and PHY
regulator regulator
- reg-names: The names of register regions. The following regions are required: - reg-names: The names of register regions. The following regions are required:
......
...@@ -2,18 +2,28 @@ Qualcomm adreno/snapdragon display controller ...@@ -2,18 +2,28 @@ Qualcomm adreno/snapdragon display controller
Required properties: Required properties:
- compatible: - compatible:
* "qcom,mdp" - mdp4 * "qcom,mdp4" - mdp4
* "qcom,mdp5" - mdp5
- reg: Physical base address and length of the controller's registers. - reg: Physical base address and length of the controller's registers.
- interrupts: The interrupt signal from the display controller. - interrupts: The interrupt signal from the display controller.
- connectors: array of phandles for output device(s) - connectors: array of phandles for output device(s)
- clocks: device clocks - clocks: device clocks
See ../clocks/clock-bindings.txt for details. See ../clocks/clock-bindings.txt for details.
- clock-names: the following clocks are required: - clock-names: the following clocks are required.
For MDP4:
* "core_clk" * "core_clk"
* "iface_clk" * "iface_clk"
* "lut_clk"
* "src_clk" * "src_clk"
* "hdmi_clk" * "hdmi_clk"
* "mpd_clk" * "mdp_clk"
For MDP5:
* "bus_clk"
* "iface_clk"
* "core_clk_src"
* "core_clk"
* "lut_clk" (some MDP5 versions may not need this)
* "vsync_clk"
Optional properties: Optional properties:
- gpus: phandle for gpu device - gpus: phandle for gpu device
...@@ -26,7 +36,7 @@ Example: ...@@ -26,7 +36,7 @@ Example:
... ...
mdp: qcom,mdp@5100000 { mdp: qcom,mdp@5100000 {
compatible = "qcom,mdp"; compatible = "qcom,mdp4";
reg = <0x05100000 0xf0000>; reg = <0x05100000 0xf0000>;
interrupts = <GIC_SPI 75 0>; interrupts = <GIC_SPI 75 0>;
connectors = <&hdmi>; connectors = <&hdmi>;
......
...@@ -54,3 +54,11 @@ config DRM_MSM_DSI_20NM_PHY ...@@ -54,3 +54,11 @@ config DRM_MSM_DSI_20NM_PHY
default y default y
help help
Choose this option if the 20nm DSI PHY is used on the platform. Choose this option if the 20nm DSI PHY is used on the platform.
config DRM_MSM_DSI_28NM_8960_PHY
bool "Enable DSI 28nm 8960 PHY driver in MSM DRM"
depends on DRM_MSM_DSI
default y
help
Choose this option if the 28nm DSI PHY 8960 variant is used on the
platform.
...@@ -54,6 +54,7 @@ msm-$(CONFIG_DRM_FBDEV_EMULATION) += msm_fbdev.o ...@@ -54,6 +54,7 @@ msm-$(CONFIG_DRM_FBDEV_EMULATION) += msm_fbdev.o
msm-$(CONFIG_COMMON_CLK) += mdp/mdp4/mdp4_lvds_pll.o msm-$(CONFIG_COMMON_CLK) += mdp/mdp4/mdp4_lvds_pll.o
msm-$(CONFIG_DRM_MSM_DSI) += dsi/dsi.o \ msm-$(CONFIG_DRM_MSM_DSI) += dsi/dsi.o \
mdp/mdp4/mdp4_dsi_encoder.o \
dsi/dsi_cfg.o \ dsi/dsi_cfg.o \
dsi/dsi_host.o \ dsi/dsi_host.o \
dsi/dsi_manager.o \ dsi/dsi_manager.o \
...@@ -62,10 +63,12 @@ msm-$(CONFIG_DRM_MSM_DSI) += dsi/dsi.o \ ...@@ -62,10 +63,12 @@ msm-$(CONFIG_DRM_MSM_DSI) += dsi/dsi.o \
msm-$(CONFIG_DRM_MSM_DSI_28NM_PHY) += dsi/phy/dsi_phy_28nm.o msm-$(CONFIG_DRM_MSM_DSI_28NM_PHY) += dsi/phy/dsi_phy_28nm.o
msm-$(CONFIG_DRM_MSM_DSI_20NM_PHY) += dsi/phy/dsi_phy_20nm.o msm-$(CONFIG_DRM_MSM_DSI_20NM_PHY) += dsi/phy/dsi_phy_20nm.o
msm-$(CONFIG_DRM_MSM_DSI_28NM_8960_PHY) += dsi/phy/dsi_phy_28nm_8960.o
ifeq ($(CONFIG_DRM_MSM_DSI_PLL),y) ifeq ($(CONFIG_DRM_MSM_DSI_PLL),y)
msm-y += dsi/pll/dsi_pll.o msm-y += dsi/pll/dsi_pll.o
msm-$(CONFIG_DRM_MSM_DSI_28NM_PHY) += dsi/pll/dsi_pll_28nm.o msm-$(CONFIG_DRM_MSM_DSI_28NM_PHY) += dsi/pll/dsi_pll_28nm.o
msm-$(CONFIG_DRM_MSM_DSI_28NM_8960_PHY) += dsi/pll/dsi_pll_28nm_8960.o
endif endif
obj-$(CONFIG_DRM_MSM) += msm.o obj-$(CONFIG_DRM_MSM) += msm.o
...@@ -19,10 +19,6 @@ ...@@ -19,10 +19,6 @@
#include "adreno_gpu.h" #include "adreno_gpu.h"
#if defined(DOWNSTREAM_CONFIG_MSM_BUS_SCALING) && !defined(CONFIG_OF)
# include <mach/kgsl.h>
#endif
#define ANY_ID 0xff #define ANY_ID 0xff
bool hang_debug = false; bool hang_debug = false;
...@@ -168,7 +164,6 @@ static void set_gpu_pdev(struct drm_device *dev, ...@@ -168,7 +164,6 @@ static void set_gpu_pdev(struct drm_device *dev,
static int adreno_bind(struct device *dev, struct device *master, void *data) static int adreno_bind(struct device *dev, struct device *master, void *data)
{ {
static struct adreno_platform_config config = {}; static struct adreno_platform_config config = {};
#ifdef CONFIG_OF
struct device_node *child, *node = dev->of_node; struct device_node *child, *node = dev->of_node;
u32 val; u32 val;
int ret; int ret;
...@@ -205,53 +200,6 @@ static int adreno_bind(struct device *dev, struct device *master, void *data) ...@@ -205,53 +200,6 @@ static int adreno_bind(struct device *dev, struct device *master, void *data)
return -ENXIO; return -ENXIO;
} }
#else
struct kgsl_device_platform_data *pdata = dev->platform_data;
uint32_t version = socinfo_get_version();
if (cpu_is_apq8064ab()) {
config.fast_rate = 450000000;
config.slow_rate = 27000000;
config.bus_freq = 4;
config.rev = ADRENO_REV(3, 2, 1, 0);
} else if (cpu_is_apq8064()) {
config.fast_rate = 400000000;
config.slow_rate = 27000000;
config.bus_freq = 4;
if (SOCINFO_VERSION_MAJOR(version) == 2)
config.rev = ADRENO_REV(3, 2, 0, 2);
else if ((SOCINFO_VERSION_MAJOR(version) == 1) &&
(SOCINFO_VERSION_MINOR(version) == 1))
config.rev = ADRENO_REV(3, 2, 0, 1);
else
config.rev = ADRENO_REV(3, 2, 0, 0);
} else if (cpu_is_msm8960ab()) {
config.fast_rate = 400000000;
config.slow_rate = 320000000;
config.bus_freq = 4;
if (SOCINFO_VERSION_MINOR(version) == 0)
config.rev = ADRENO_REV(3, 2, 1, 0);
else
config.rev = ADRENO_REV(3, 2, 1, 1);
} else if (cpu_is_msm8930()) {
config.fast_rate = 400000000;
config.slow_rate = 27000000;
config.bus_freq = 3;
if ((SOCINFO_VERSION_MAJOR(version) == 1) &&
(SOCINFO_VERSION_MINOR(version) == 2))
config.rev = ADRENO_REV(3, 0, 5, 2);
else
config.rev = ADRENO_REV(3, 0, 5, 0);
}
# ifdef DOWNSTREAM_CONFIG_MSM_BUS_SCALING
config.bus_scale_table = pdata->bus_scale_table;
# endif
#endif
dev->platform_data = &config; dev->platform_data = &config;
set_gpu_pdev(dev_get_drvdata(master), to_platform_device(dev)); set_gpu_pdev(dev_get_drvdata(master), to_platform_device(dev));
return 0; return 0;
......
...@@ -31,10 +31,12 @@ enum msm_dsi_phy_type { ...@@ -31,10 +31,12 @@ enum msm_dsi_phy_type {
MSM_DSI_PHY_28NM_HPM, MSM_DSI_PHY_28NM_HPM,
MSM_DSI_PHY_28NM_LP, MSM_DSI_PHY_28NM_LP,
MSM_DSI_PHY_20NM, MSM_DSI_PHY_20NM,
MSM_DSI_PHY_28NM_8960,
MSM_DSI_PHY_MAX MSM_DSI_PHY_MAX
}; };
#define DSI_DEV_REGULATOR_MAX 8 #define DSI_DEV_REGULATOR_MAX 8
#define DSI_BUS_CLK_MAX 4
/* Regulators for DSI devices */ /* Regulators for DSI devices */
struct dsi_reg_entry { struct dsi_reg_entry {
...@@ -89,7 +91,7 @@ int msm_dsi_manager_phy_enable(int id, ...@@ -89,7 +91,7 @@ int msm_dsi_manager_phy_enable(int id,
u32 *clk_pre, u32 *clk_post); u32 *clk_pre, u32 *clk_post);
void msm_dsi_manager_phy_disable(int id); void msm_dsi_manager_phy_disable(int id);
int msm_dsi_manager_cmd_xfer(int id, const struct mipi_dsi_msg *msg); 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); bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 dma_base, u32 len);
int msm_dsi_manager_register(struct msm_dsi *msm_dsi); int msm_dsi_manager_register(struct msm_dsi *msm_dsi);
void msm_dsi_manager_unregister(struct msm_dsi *msm_dsi); void msm_dsi_manager_unregister(struct msm_dsi *msm_dsi);
...@@ -143,7 +145,7 @@ int msm_dsi_host_cmd_tx(struct mipi_dsi_host *host, ...@@ -143,7 +145,7 @@ int msm_dsi_host_cmd_tx(struct mipi_dsi_host *host,
int msm_dsi_host_cmd_rx(struct mipi_dsi_host *host, int msm_dsi_host_cmd_rx(struct mipi_dsi_host *host,
const struct mipi_dsi_msg *msg); const struct mipi_dsi_msg *msg);
void msm_dsi_host_cmd_xfer_commit(struct mipi_dsi_host *host, void msm_dsi_host_cmd_xfer_commit(struct mipi_dsi_host *host,
u32 iova, u32 len); u32 dma_base, u32 len);
int msm_dsi_host_enable(struct mipi_dsi_host *host); int msm_dsi_host_enable(struct mipi_dsi_host *host);
int msm_dsi_host_disable(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_on(struct mipi_dsi_host *host);
......
...@@ -13,9 +13,26 @@ ...@@ -13,9 +13,26 @@
#include "dsi_cfg.h" #include "dsi_cfg.h"
/* DSI v2 has not been supported by now */ static const char * const dsi_v2_bus_clk_names[] = {
static const struct msm_dsi_config dsi_v2_cfg = { "core_mmss_clk", "iface_clk", "bus_clk",
};
static const struct msm_dsi_config apq8064_dsi_cfg = {
.io_offset = 0, .io_offset = 0,
.reg_cfg = {
.num = 3,
.regs = {
{"vdda", 1200000, 1200000, 100000, 100},
{"avdd", 3000000, 3000000, 110000, 100},
{"vddio", 1800000, 1800000, 100000, 100},
},
},
.bus_clk_names = dsi_v2_bus_clk_names,
.num_bus_clks = ARRAY_SIZE(dsi_v2_bus_clk_names),
};
static const char * const dsi_6g_bus_clk_names[] = {
"mdp_core_clk", "iface_clk", "bus_clk", "core_mmss_clk",
}; };
static const struct msm_dsi_config msm8974_apq8084_dsi_cfg = { static const struct msm_dsi_config msm8974_apq8084_dsi_cfg = {
...@@ -29,6 +46,12 @@ static const struct msm_dsi_config msm8974_apq8084_dsi_cfg = { ...@@ -29,6 +46,12 @@ static const struct msm_dsi_config msm8974_apq8084_dsi_cfg = {
{"vddio", 1800000, 1800000, 100000, 100}, {"vddio", 1800000, 1800000, 100000, 100},
}, },
}, },
.bus_clk_names = dsi_6g_bus_clk_names,
.num_bus_clks = ARRAY_SIZE(dsi_6g_bus_clk_names),
};
static const char * const dsi_8916_bus_clk_names[] = {
"mdp_core_clk", "iface_clk", "bus_clk",
}; };
static const struct msm_dsi_config msm8916_dsi_cfg = { static const struct msm_dsi_config msm8916_dsi_cfg = {
...@@ -42,6 +65,8 @@ static const struct msm_dsi_config msm8916_dsi_cfg = { ...@@ -42,6 +65,8 @@ static const struct msm_dsi_config msm8916_dsi_cfg = {
{"vddio", 1800000, 1800000, 100000, 100}, {"vddio", 1800000, 1800000, 100000, 100},
}, },
}, },
.bus_clk_names = dsi_8916_bus_clk_names,
.num_bus_clks = ARRAY_SIZE(dsi_8916_bus_clk_names),
}; };
static const struct msm_dsi_config msm8994_dsi_cfg = { static const struct msm_dsi_config msm8994_dsi_cfg = {
...@@ -57,11 +82,13 @@ static const struct msm_dsi_config msm8994_dsi_cfg = { ...@@ -57,11 +82,13 @@ static const struct msm_dsi_config msm8994_dsi_cfg = {
{"lab_reg", -1, -1, -1, -1}, {"lab_reg", -1, -1, -1, -1},
{"ibb_reg", -1, -1, -1, -1}, {"ibb_reg", -1, -1, -1, -1},
}, },
} },
.bus_clk_names = dsi_6g_bus_clk_names,
.num_bus_clks = ARRAY_SIZE(dsi_6g_bus_clk_names),
}; };
static const struct msm_dsi_cfg_handler dsi_cfg_handlers[] = { static const struct msm_dsi_cfg_handler dsi_cfg_handlers[] = {
{MSM_DSI_VER_MAJOR_V2, U32_MAX, &dsi_v2_cfg}, {MSM_DSI_VER_MAJOR_V2, MSM_DSI_V2_VER_MINOR_8064, &apq8064_dsi_cfg},
{MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_0, {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_0,
&msm8974_apq8084_dsi_cfg}, &msm8974_apq8084_dsi_cfg},
{MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_1, {MSM_DSI_VER_MAJOR_6G, MSM_DSI_6G_VER_MINOR_V1_1,
......
...@@ -25,11 +25,15 @@ ...@@ -25,11 +25,15 @@
#define MSM_DSI_6G_VER_MINOR_V1_3 0x10030000 #define MSM_DSI_6G_VER_MINOR_V1_3 0x10030000
#define MSM_DSI_6G_VER_MINOR_V1_3_1 0x10030001 #define MSM_DSI_6G_VER_MINOR_V1_3_1 0x10030001
#define MSM_DSI_V2_VER_MINOR_8064 0x0
#define DSI_6G_REG_SHIFT 4 #define DSI_6G_REG_SHIFT 4
struct msm_dsi_config { struct msm_dsi_config {
u32 io_offset; u32 io_offset;
struct dsi_reg_config reg_cfg; struct dsi_reg_config reg_cfg;
const char * const *bus_clk_names;
const int num_bus_clks;
}; };
struct msm_dsi_cfg_handler { struct msm_dsi_cfg_handler {
......
This diff is collapsed.
...@@ -774,7 +774,7 @@ int msm_dsi_manager_cmd_xfer(int id, const struct mipi_dsi_msg *msg) ...@@ -774,7 +774,7 @@ int msm_dsi_manager_cmd_xfer(int id, const struct mipi_dsi_msg *msg)
return ret; return ret;
} }
bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 iova, u32 len) bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 dma_base, u32 len)
{ {
struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id); struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
struct msm_dsi *msm_dsi0 = dsi_mgr_get_dsi(DSI_0); struct msm_dsi *msm_dsi0 = dsi_mgr_get_dsi(DSI_0);
...@@ -784,9 +784,9 @@ bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 iova, u32 len) ...@@ -784,9 +784,9 @@ bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 iova, u32 len)
return false; return false;
if (IS_SYNC_NEEDED() && msm_dsi0) if (IS_SYNC_NEEDED() && msm_dsi0)
msm_dsi_host_cmd_xfer_commit(msm_dsi0->host, iova, len); msm_dsi_host_cmd_xfer_commit(msm_dsi0->host, dma_base, len);
msm_dsi_host_cmd_xfer_commit(host, iova, len); msm_dsi_host_cmd_xfer_commit(host, dma_base, len);
return true; return true;
} }
......
...@@ -276,6 +276,10 @@ static const struct of_device_id dsi_phy_dt_match[] = { ...@@ -276,6 +276,10 @@ static const struct of_device_id dsi_phy_dt_match[] = {
#ifdef CONFIG_DRM_MSM_DSI_20NM_PHY #ifdef CONFIG_DRM_MSM_DSI_20NM_PHY
{ .compatible = "qcom,dsi-phy-20nm", { .compatible = "qcom,dsi-phy-20nm",
.data = &dsi_phy_20nm_cfgs }, .data = &dsi_phy_20nm_cfgs },
#endif
#ifdef CONFIG_DRM_MSM_DSI_28NM_8960_PHY
{ .compatible = "qcom,dsi-phy-28nm-8960",
.data = &dsi_phy_28nm_8960_cfgs },
#endif #endif
{} {}
}; };
......
...@@ -43,6 +43,7 @@ struct msm_dsi_phy_cfg { ...@@ -43,6 +43,7 @@ struct msm_dsi_phy_cfg {
extern const struct msm_dsi_phy_cfg dsi_phy_28nm_hpm_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_28nm_hpm_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_28nm_lp_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_28nm_lp_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_20nm_cfgs; extern const struct msm_dsi_phy_cfg dsi_phy_20nm_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_28nm_8960_cfgs;
struct msm_dsi_dphy_timing { struct msm_dsi_dphy_timing {
u32 clk_pre; u32 clk_pre;
......
/*
* Copyright (c) 2012-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_phy.h"
#include "dsi.xml.h"
static void dsi_28nm_dphy_set_timing(struct msm_dsi_phy *phy,
struct msm_dsi_dphy_timing *timing)
{
void __iomem *base = phy->base;
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_0,
DSI_28nm_8960_PHY_TIMING_CTRL_0_CLK_ZERO(timing->clk_zero));
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_1,
DSI_28nm_8960_PHY_TIMING_CTRL_1_CLK_TRAIL(timing->clk_trail));
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_2,
DSI_28nm_8960_PHY_TIMING_CTRL_2_CLK_PREPARE(timing->clk_prepare));
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_3, 0x0);
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_4,
DSI_28nm_8960_PHY_TIMING_CTRL_4_HS_EXIT(timing->hs_exit));
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_5,
DSI_28nm_8960_PHY_TIMING_CTRL_5_HS_ZERO(timing->hs_zero));
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_6,
DSI_28nm_8960_PHY_TIMING_CTRL_6_HS_PREPARE(timing->hs_prepare));
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_7,
DSI_28nm_8960_PHY_TIMING_CTRL_7_HS_TRAIL(timing->hs_trail));
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_8,
DSI_28nm_8960_PHY_TIMING_CTRL_8_HS_RQST(timing->hs_rqst));
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_9,
DSI_28nm_8960_PHY_TIMING_CTRL_9_TA_GO(timing->ta_go) |
DSI_28nm_8960_PHY_TIMING_CTRL_9_TA_SURE(timing->ta_sure));
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_10,
DSI_28nm_8960_PHY_TIMING_CTRL_10_TA_GET(timing->ta_get));
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_TIMING_CTRL_11,
DSI_28nm_8960_PHY_TIMING_CTRL_11_TRIG3_CMD(0));
}
static void dsi_28nm_phy_regulator_init(struct msm_dsi_phy *phy)
{
void __iomem *base = phy->reg_base;
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_0, 0x3);
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_1, 1);
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_2, 1);
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_3, 0);
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_4,
0x100);
}
static void dsi_28nm_phy_regulator_ctrl(struct msm_dsi_phy *phy)
{
void __iomem *base = phy->reg_base;
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_0, 0x3);
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_1, 0xa);
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_2, 0x4);
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_3, 0x0);
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CTRL_4, 0x20);
}
static void dsi_28nm_phy_calibration(struct msm_dsi_phy *phy)
{
void __iomem *base = phy->reg_base;
u32 status;
int i = 5000;
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_REGULATOR_CAL_PWR_CFG,
0x3);
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_CAL_SW_CFG_2, 0x0);
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_CAL_HW_CFG_1, 0x5a);
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_CAL_HW_CFG_3, 0x10);
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_CAL_HW_CFG_4, 0x1);
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_CAL_HW_CFG_0, 0x1);
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_CAL_HW_TRIGGER, 0x1);
usleep_range(5000, 6000);
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_MISC_CAL_HW_TRIGGER, 0x0);
do {
status = dsi_phy_read(base +
REG_DSI_28nm_8960_PHY_MISC_CAL_STATUS);
if (!(status & DSI_28nm_8960_PHY_MISC_CAL_STATUS_CAL_BUSY))
break;
udelay(1);
} while (--i > 0);
}
static void dsi_28nm_phy_lane_config(struct msm_dsi_phy *phy)
{
void __iomem *base = phy->base;
int i;
for (i = 0; i < 4; i++) {
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LN_CFG_0(i), 0x80);
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LN_CFG_1(i), 0x45);
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LN_CFG_2(i), 0x00);
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LN_TEST_DATAPATH(i),
0x00);
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LN_TEST_STR_0(i),
0x01);
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LN_TEST_STR_1(i),
0x66);
}
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LNCK_CFG_0, 0x40);
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LNCK_CFG_1, 0x67);
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LNCK_CFG_2, 0x0);
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LNCK_TEST_DATAPATH, 0x0);
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LNCK_TEST_STR0, 0x1);
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LNCK_TEST_STR1, 0x88);
}
static int dsi_28nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
const unsigned long bit_rate, const unsigned long esc_rate)
{
struct msm_dsi_dphy_timing *timing = &phy->timing;
void __iomem *base = phy->base;
DBG("");
if (msm_dsi_dphy_timing_calc(timing, bit_rate, esc_rate)) {
dev_err(&phy->pdev->dev,
"%s: D-PHY timing calculation failed\n", __func__);
return -EINVAL;
}
dsi_28nm_phy_regulator_init(phy);
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_LDO_CTRL, 0x04);
/* strength control */
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_STRENGTH_0, 0xff);
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_STRENGTH_1, 0x00);
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_STRENGTH_2, 0x06);
/* phy ctrl */
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_CTRL_0, 0x5f);
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_CTRL_1, 0x00);
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_CTRL_2, 0x00);
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_CTRL_3, 0x10);
dsi_28nm_phy_regulator_ctrl(phy);
dsi_28nm_phy_calibration(phy);
dsi_28nm_phy_lane_config(phy);
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_BIST_CTRL_4, 0x0f);
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_BIST_CTRL_1, 0x03);
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_BIST_CTRL_0, 0x03);
dsi_phy_write(base + REG_DSI_28nm_8960_PHY_BIST_CTRL_4, 0x0);
dsi_28nm_dphy_set_timing(phy, timing);
return 0;
}
static void dsi_28nm_phy_disable(struct msm_dsi_phy *phy)
{
dsi_phy_write(phy->base + REG_DSI_28nm_8960_PHY_CTRL_0, 0x0);
/*
* Wait for the registers writes to complete in order to
* ensure that the phy is completely disabled
*/
wmb();
}
const struct msm_dsi_phy_cfg dsi_phy_28nm_8960_cfgs = {
.type = MSM_DSI_PHY_28NM_8960,
.src_pll_truthtable = { {true, true}, {false, true} },
.reg_cfg = {
.num = 1,
.regs = {
{"vddio", 1800000, 1800000, 100000, 100},
},
},
.ops = {
.enable = dsi_28nm_phy_enable,
.disable = dsi_28nm_phy_disable,
},
};
...@@ -151,6 +151,9 @@ struct msm_dsi_pll *msm_dsi_pll_init(struct platform_device *pdev, ...@@ -151,6 +151,9 @@ struct msm_dsi_pll *msm_dsi_pll_init(struct platform_device *pdev,
case MSM_DSI_PHY_28NM_LP: case MSM_DSI_PHY_28NM_LP:
pll = msm_dsi_pll_28nm_init(pdev, type, id); pll = msm_dsi_pll_28nm_init(pdev, type, id);
break; break;
case MSM_DSI_PHY_28NM_8960:
pll = msm_dsi_pll_28nm_8960_init(pdev, id);
break;
default: default:
pll = ERR_PTR(-ENXIO); pll = ERR_PTR(-ENXIO);
break; break;
......
...@@ -93,6 +93,16 @@ static inline struct msm_dsi_pll *msm_dsi_pll_28nm_init( ...@@ -93,6 +93,16 @@ static inline struct msm_dsi_pll *msm_dsi_pll_28nm_init(
return ERR_PTR(-ENODEV); return ERR_PTR(-ENODEV);
} }
#endif #endif
#ifdef CONFIG_DRM_MSM_DSI_28NM_8960_PHY
struct msm_dsi_pll *msm_dsi_pll_28nm_8960_init(struct platform_device *pdev,
int id);
#else
struct msm_dsi_pll *msm_dsi_pll_28nm_8960_init(struct platform_device *pdev,
int id)
{
return ERR_PTR(-ENODEV);
}
#endif
#endif /* __DSI_PLL_H__ */ #endif /* __DSI_PLL_H__ */
This diff is collapsed.
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
*/ */
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include "hdmi.h" #include "hdmi.h"
void hdmi_set_mode(struct hdmi *hdmi, bool power_on) void hdmi_set_mode(struct hdmi *hdmi, bool power_on)
...@@ -322,8 +324,6 @@ int hdmi_modeset_init(struct hdmi *hdmi, ...@@ -322,8 +324,6 @@ int hdmi_modeset_init(struct hdmi *hdmi,
* The hdmi device: * The hdmi device:
*/ */
#include <linux/of_gpio.h>
#define HDMI_CFG(item, entry) \ #define HDMI_CFG(item, entry) \
.item ## _names = item ##_names_ ## entry, \ .item ## _names = item ##_names_ ## entry, \
.item ## _cnt = ARRAY_SIZE(item ## _names_ ## entry) .item ## _cnt = ARRAY_SIZE(item ## _names_ ## entry)
...@@ -388,17 +388,6 @@ static struct hdmi_platform_config hdmi_tx_8996_config = { ...@@ -388,17 +388,6 @@ static struct hdmi_platform_config hdmi_tx_8996_config = {
.hpd_freq = hpd_clk_freq_8x74, .hpd_freq = hpd_clk_freq_8x74,
}; };
static const struct of_device_id dt_match[] = {
{ .compatible = "qcom,hdmi-tx-8996", .data = &hdmi_tx_8996_config },
{ .compatible = "qcom,hdmi-tx-8994", .data = &hdmi_tx_8994_config },
{ .compatible = "qcom,hdmi-tx-8084", .data = &hdmi_tx_8084_config },
{ .compatible = "qcom,hdmi-tx-8974", .data = &hdmi_tx_8974_config },
{ .compatible = "qcom,hdmi-tx-8960", .data = &hdmi_tx_8960_config },
{ .compatible = "qcom,hdmi-tx-8660", .data = &hdmi_tx_8660_config },
{}
};
#ifdef CONFIG_OF
static int get_gpio(struct device *dev, struct device_node *of_node, const char *name) static int get_gpio(struct device *dev, struct device_node *of_node, const char *name)
{ {
int gpio = of_get_named_gpio(of_node, name, 0); int gpio = of_get_named_gpio(of_node, name, 0);
...@@ -413,7 +402,6 @@ static int get_gpio(struct device *dev, struct device_node *of_node, const char ...@@ -413,7 +402,6 @@ static int get_gpio(struct device *dev, struct device_node *of_node, const char
} }
return gpio; return gpio;
} }
#endif
static int hdmi_bind(struct device *dev, struct device *master, void *data) static int hdmi_bind(struct device *dev, struct device *master, void *data)
{ {
...@@ -421,16 +409,12 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data) ...@@ -421,16 +409,12 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
struct msm_drm_private *priv = drm->dev_private; struct msm_drm_private *priv = drm->dev_private;
static struct hdmi_platform_config *hdmi_cfg; static struct hdmi_platform_config *hdmi_cfg;
struct hdmi *hdmi; struct hdmi *hdmi;
#ifdef CONFIG_OF
struct device_node *of_node = dev->of_node; struct device_node *of_node = dev->of_node;
const struct of_device_id *match;
match = of_match_node(dt_match, of_node); hdmi_cfg = (struct hdmi_platform_config *)
if (match && match->data) { of_device_get_match_data(dev);
hdmi_cfg = (struct hdmi_platform_config *)match->data; if (!hdmi_cfg) {
DBG("hdmi phy: %s", match->compatible); dev_err(dev, "unknown hdmi_cfg: %s\n", of_node->name);
} else {
dev_err(dev, "unknown phy: %s\n", of_node->name);
return -ENXIO; return -ENXIO;
} }
...@@ -443,55 +427,6 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data) ...@@ -443,55 +427,6 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
hdmi_cfg->mux_sel_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-mux-sel"); hdmi_cfg->mux_sel_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-mux-sel");
hdmi_cfg->mux_lpm_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-mux-lpm"); hdmi_cfg->mux_lpm_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-mux-lpm");
#else
static struct hdmi_platform_config config = {};
static const char *hpd_clk_names[] = {
"core_clk", "master_iface_clk", "slave_iface_clk",
};
if (cpu_is_apq8064()) {
static const char *hpd_reg_names[] = {"8921_hdmi_mvs"};
config.phy_init = hdmi_phy_8960_init;
config.hpd_reg_names = hpd_reg_names;
config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names);
config.hpd_clk_names = hpd_clk_names;
config.hpd_clk_cnt = ARRAY_SIZE(hpd_clk_names);
config.ddc_clk_gpio = 70;
config.ddc_data_gpio = 71;
config.hpd_gpio = 72;
config.mux_en_gpio = -1;
config.mux_sel_gpio = -1;
} else if (cpu_is_msm8960() || cpu_is_msm8960ab()) {
static const char *hpd_reg_names[] = {"8921_hdmi_mvs"};
config.phy_init = hdmi_phy_8960_init;
config.hpd_reg_names = hpd_reg_names;
config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names);
config.hpd_clk_names = hpd_clk_names;
config.hpd_clk_cnt = ARRAY_SIZE(hpd_clk_names);
config.ddc_clk_gpio = 100;
config.ddc_data_gpio = 101;
config.hpd_gpio = 102;
config.mux_en_gpio = -1;
config.mux_sel_gpio = -1;
} else if (cpu_is_msm8x60()) {
static const char *hpd_reg_names[] = {
"8901_hdmi_mvs", "8901_mpp0"
};
config.phy_init = hdmi_phy_8x60_init;
config.hpd_reg_names = hpd_reg_names;
config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names);
config.hpd_clk_names = hpd_clk_names;
config.hpd_clk_cnt = ARRAY_SIZE(hpd_clk_names);
config.ddc_clk_gpio = 170;
config.ddc_data_gpio = 171;
config.hpd_gpio = 172;
config.mux_en_gpio = -1;
config.mux_sel_gpio = -1;
}
config.mmio_name = "hdmi_msm_hdmi_addr";
config.qfprom_mmio_name = "hdmi_msm_qfprom_addr";
hdmi_cfg = &config;
#endif
dev->platform_data = hdmi_cfg; dev->platform_data = hdmi_cfg;
hdmi = hdmi_init(to_platform_device(dev)); hdmi = hdmi_init(to_platform_device(dev));
...@@ -529,6 +464,16 @@ static int hdmi_dev_remove(struct platform_device *pdev) ...@@ -529,6 +464,16 @@ static int hdmi_dev_remove(struct platform_device *pdev)
return 0; return 0;
} }
static const struct of_device_id dt_match[] = {
{ .compatible = "qcom,hdmi-tx-8996", .data = &hdmi_tx_8996_config },
{ .compatible = "qcom,hdmi-tx-8994", .data = &hdmi_tx_8994_config },
{ .compatible = "qcom,hdmi-tx-8084", .data = &hdmi_tx_8084_config },
{ .compatible = "qcom,hdmi-tx-8974", .data = &hdmi_tx_8974_config },
{ .compatible = "qcom,hdmi-tx-8960", .data = &hdmi_tx_8960_config },
{ .compatible = "qcom,hdmi-tx-8660", .data = &hdmi_tx_8660_config },
{}
};
static struct platform_driver hdmi_driver = { static struct platform_driver hdmi_driver = {
.probe = hdmi_dev_probe, .probe = hdmi_dev_probe,
.remove = hdmi_dev_remove, .remove = hdmi_dev_remove,
......
/*
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
* Copyright (c) 2014, Inforce Computing. All rights reserved.
*
* Author: Vinay Simha <vinaysimha@inforcecomputing.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* 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.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "mdp4_kms.h"
#include "drm_crtc.h"
#include "drm_crtc_helper.h"
struct mdp4_dsi_encoder {
struct drm_encoder base;
struct drm_panel *panel;
bool enabled;
};
#define to_mdp4_dsi_encoder(x) container_of(x, struct mdp4_dsi_encoder, base)
static struct mdp4_kms *get_kms(struct drm_encoder *encoder)
{
struct msm_drm_private *priv = encoder->dev->dev_private;
return to_mdp4_kms(to_mdp_kms(priv->kms));
}
static void mdp4_dsi_encoder_destroy(struct drm_encoder *encoder)
{
struct mdp4_dsi_encoder *mdp4_dsi_encoder = to_mdp4_dsi_encoder(encoder);
drm_encoder_cleanup(encoder);
kfree(mdp4_dsi_encoder);
}
static const struct drm_encoder_funcs mdp4_dsi_encoder_funcs = {
.destroy = mdp4_dsi_encoder_destroy,
};
static bool mdp4_dsi_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static void mdp4_dsi_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
struct mdp4_kms *mdp4_kms = get_kms(encoder);
uint32_t dsi_hsync_skew, vsync_period, vsync_len, ctrl_pol;
uint32_t display_v_start, display_v_end;
uint32_t hsync_start_x, hsync_end_x;
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);
ctrl_pol = 0;
if (mode->flags & DRM_MODE_FLAG_NHSYNC)
ctrl_pol |= MDP4_DSI_CTRL_POLARITY_HSYNC_LOW;
if (mode->flags & DRM_MODE_FLAG_NVSYNC)
ctrl_pol |= MDP4_DSI_CTRL_POLARITY_VSYNC_LOW;
/* probably need to get DATA_EN polarity from panel.. */
dsi_hsync_skew = 0; /* get this from panel? */
hsync_start_x = (mode->htotal - mode->hsync_start);
hsync_end_x = mode->htotal - (mode->hsync_start - mode->hdisplay) - 1;
vsync_period = mode->vtotal * mode->htotal;
vsync_len = (mode->vsync_end - mode->vsync_start) * mode->htotal;
display_v_start = (mode->vtotal - mode->vsync_start) * mode->htotal + dsi_hsync_skew;
display_v_end = vsync_period - ((mode->vsync_start - mode->vdisplay) * mode->htotal) + dsi_hsync_skew - 1;
mdp4_write(mdp4_kms, REG_MDP4_DSI_HSYNC_CTRL,
MDP4_DSI_HSYNC_CTRL_PULSEW(mode->hsync_end - mode->hsync_start) |
MDP4_DSI_HSYNC_CTRL_PERIOD(mode->htotal));
mdp4_write(mdp4_kms, REG_MDP4_DSI_VSYNC_PERIOD, vsync_period);
mdp4_write(mdp4_kms, REG_MDP4_DSI_VSYNC_LEN, vsync_len);
mdp4_write(mdp4_kms, REG_MDP4_DSI_DISPLAY_HCTRL,
MDP4_DSI_DISPLAY_HCTRL_START(hsync_start_x) |
MDP4_DSI_DISPLAY_HCTRL_END(hsync_end_x));
mdp4_write(mdp4_kms, REG_MDP4_DSI_DISPLAY_VSTART, display_v_start);
mdp4_write(mdp4_kms, REG_MDP4_DSI_DISPLAY_VEND, display_v_end);
mdp4_write(mdp4_kms, REG_MDP4_DSI_CTRL_POLARITY, ctrl_pol);
mdp4_write(mdp4_kms, REG_MDP4_DSI_UNDERFLOW_CLR,
MDP4_DSI_UNDERFLOW_CLR_ENABLE_RECOVERY |
MDP4_DSI_UNDERFLOW_CLR_COLOR(0xff));
mdp4_write(mdp4_kms, REG_MDP4_DSI_ACTIVE_HCTL,
MDP4_DSI_ACTIVE_HCTL_START(0) |
MDP4_DSI_ACTIVE_HCTL_END(0));
mdp4_write(mdp4_kms, REG_MDP4_DSI_HSYNC_SKEW, dsi_hsync_skew);
mdp4_write(mdp4_kms, REG_MDP4_DSI_BORDER_CLR, 0);
mdp4_write(mdp4_kms, REG_MDP4_DSI_ACTIVE_VSTART, 0);
mdp4_write(mdp4_kms, REG_MDP4_DSI_ACTIVE_VEND, 0);
}
static void mdp4_dsi_encoder_disable(struct drm_encoder *encoder)
{
struct mdp4_dsi_encoder *mdp4_dsi_encoder = to_mdp4_dsi_encoder(encoder);
struct mdp4_kms *mdp4_kms = get_kms(encoder);
if (!mdp4_dsi_encoder->enabled)
return;
mdp4_write(mdp4_kms, REG_MDP4_DSI_ENABLE, 0);
/*
* Wait for a vsync so we know the ENABLE=0 latched before
* the (connector) source of the vsync's gets disabled,
* otherwise we end up in a funny state if we re-enable
* before the disable latches, which results that some of
* the settings changes for the new modeset (like new
* scanout buffer) don't latch properly..
*/
mdp_irq_wait(&mdp4_kms->base, MDP4_IRQ_PRIMARY_VSYNC);
mdp4_dsi_encoder->enabled = false;
}
static void mdp4_dsi_encoder_enable(struct drm_encoder *encoder)
{
struct mdp4_dsi_encoder *mdp4_dsi_encoder = to_mdp4_dsi_encoder(encoder);
struct mdp4_kms *mdp4_kms = get_kms(encoder);
if (mdp4_dsi_encoder->enabled)
return;
mdp4_crtc_set_config(encoder->crtc,
MDP4_DMA_CONFIG_PACK_ALIGN_MSB |
MDP4_DMA_CONFIG_DEFLKR_EN |
MDP4_DMA_CONFIG_DITHER_EN |
MDP4_DMA_CONFIG_R_BPC(BPC8) |
MDP4_DMA_CONFIG_G_BPC(BPC8) |
MDP4_DMA_CONFIG_B_BPC(BPC8) |
MDP4_DMA_CONFIG_PACK(0x21));
mdp4_crtc_set_intf(encoder->crtc, INTF_DSI_VIDEO, 0);
mdp4_write(mdp4_kms, REG_MDP4_DSI_ENABLE, 1);
mdp4_dsi_encoder->enabled = true;
}
static const struct drm_encoder_helper_funcs mdp4_dsi_encoder_helper_funcs = {
.mode_fixup = mdp4_dsi_encoder_mode_fixup,
.mode_set = mdp4_dsi_encoder_mode_set,
.disable = mdp4_dsi_encoder_disable,
.enable = mdp4_dsi_encoder_enable,
};
/* initialize encoder */
struct drm_encoder *mdp4_dsi_encoder_init(struct drm_device *dev)
{
struct drm_encoder *encoder = NULL;
struct mdp4_dsi_encoder *mdp4_dsi_encoder;
int ret;
mdp4_dsi_encoder = kzalloc(sizeof(*mdp4_dsi_encoder), GFP_KERNEL);
if (!mdp4_dsi_encoder) {
ret = -ENOMEM;
goto fail;
}
encoder = &mdp4_dsi_encoder->base;
drm_encoder_init(dev, encoder, &mdp4_dsi_encoder_funcs,
DRM_MODE_ENCODER_DSI);
drm_encoder_helper_add(encoder, &mdp4_dsi_encoder_helper_funcs);
return encoder;
fail:
if (encoder)
mdp4_dsi_encoder_destroy(encoder);
return ERR_PTR(ret);
}
...@@ -29,7 +29,7 @@ void mdp4_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask, ...@@ -29,7 +29,7 @@ void mdp4_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask,
static void mdp4_irq_error_handler(struct mdp_irq *irq, uint32_t irqstatus) static void mdp4_irq_error_handler(struct mdp_irq *irq, uint32_t irqstatus)
{ {
DRM_ERROR("errors: %08x\n", irqstatus); DRM_ERROR_RATELIMITED("errors: %08x\n", irqstatus);
} }
void mdp4_irq_preinstall(struct msm_kms *kms) void mdp4_irq_preinstall(struct msm_kms *kms)
......
...@@ -169,7 +169,14 @@ static long mdp4_round_pixclk(struct msm_kms *kms, unsigned long rate, ...@@ -169,7 +169,14 @@ static long mdp4_round_pixclk(struct msm_kms *kms, unsigned long rate,
struct drm_encoder *encoder) struct drm_encoder *encoder)
{ {
/* if we had >1 encoder, we'd need something more clever: */ /* if we had >1 encoder, we'd need something more clever: */
switch (encoder->encoder_type) {
case DRM_MODE_ENCODER_TMDS:
return mdp4_dtv_round_pixclk(encoder, rate); return mdp4_dtv_round_pixclk(encoder, rate);
case DRM_MODE_ENCODER_LVDS:
case DRM_MODE_ENCODER_DSI:
default:
return rate;
}
} }
static void mdp4_preclose(struct msm_kms *kms, struct drm_file *file) static void mdp4_preclose(struct msm_kms *kms, struct drm_file *file)
...@@ -240,19 +247,18 @@ int mdp4_enable(struct mdp4_kms *mdp4_kms) ...@@ -240,19 +247,18 @@ int mdp4_enable(struct mdp4_kms *mdp4_kms)
return 0; return 0;
} }
#ifdef CONFIG_OF static struct device_node *mdp4_detect_lcdc_panel(struct drm_device *dev)
static struct drm_panel *detect_panel(struct drm_device *dev)
{ {
struct device_node *endpoint, *panel_node; struct device_node *endpoint, *panel_node;
struct device_node *np = dev->dev->of_node; struct device_node *np = dev->dev->of_node;
struct drm_panel *panel = NULL;
endpoint = of_graph_get_next_endpoint(np, NULL); endpoint = of_graph_get_next_endpoint(np, NULL);
if (!endpoint) { if (!endpoint) {
dev_err(dev->dev, "no valid endpoint\n"); DBG("no endpoint in MDP4 to fetch LVDS panel\n");
return ERR_PTR(-ENODEV); return NULL;
} }
/* don't proceed if we have an endpoint but no panel_node tied to it */
panel_node = of_graph_get_remote_port_parent(endpoint); panel_node = of_graph_get_remote_port_parent(endpoint);
if (!panel_node) { if (!panel_node) {
dev_err(dev->dev, "no valid panel node\n"); dev_err(dev->dev, "no valid panel node\n");
...@@ -262,132 +268,185 @@ static struct drm_panel *detect_panel(struct drm_device *dev) ...@@ -262,132 +268,185 @@ static struct drm_panel *detect_panel(struct drm_device *dev)
of_node_put(endpoint); of_node_put(endpoint);
panel = of_drm_find_panel(panel_node); return panel_node;
if (!panel) {
of_node_put(panel_node);
return ERR_PTR(-EPROBE_DEFER);
}
return panel;
} }
#else
static struct drm_panel *detect_panel(struct drm_device *dev)
{
// ??? maybe use a module param to specify which panel is attached?
}
#endif
static int modeset_init(struct mdp4_kms *mdp4_kms) static int mdp4_modeset_init_intf(struct mdp4_kms *mdp4_kms,
int intf_type)
{ {
struct drm_device *dev = mdp4_kms->dev; struct drm_device *dev = mdp4_kms->dev;
struct msm_drm_private *priv = dev->dev_private; struct msm_drm_private *priv = dev->dev_private;
struct drm_plane *plane;
struct drm_crtc *crtc;
struct drm_encoder *encoder; struct drm_encoder *encoder;
struct drm_connector *connector; struct drm_connector *connector;
struct drm_panel *panel; struct device_node *panel_node;
struct drm_encoder *dsi_encs[MSM_DSI_ENCODER_NUM];
int i, dsi_id;
int ret; int ret;
/* construct non-private planes: */ switch (intf_type) {
plane = mdp4_plane_init(dev, VG1, false); case DRM_MODE_ENCODER_LVDS:
if (IS_ERR(plane)) {
dev_err(dev->dev, "failed to construct plane for VG1\n");
ret = PTR_ERR(plane);
goto fail;
}
priv->planes[priv->num_planes++] = plane;
plane = mdp4_plane_init(dev, VG2, false);
if (IS_ERR(plane)) {
dev_err(dev->dev, "failed to construct plane for VG2\n");
ret = PTR_ERR(plane);
goto fail;
}
priv->planes[priv->num_planes++] = plane;
/* /*
* Setup the LCDC/LVDS path: RGB2 -> DMA_P -> LCDC -> LVDS: * bail out early if:
* - there is no panel node (no need to initialize lcdc
* encoder and lvds connector), or
* - panel node is a bad pointer
*/ */
panel_node = mdp4_detect_lcdc_panel(dev);
if (IS_ERR_OR_NULL(panel_node))
return PTR_ERR(panel_node);
panel = detect_panel(dev); encoder = mdp4_lcdc_encoder_init(dev, panel_node);
if (IS_ERR(panel)) { if (IS_ERR(encoder)) {
ret = PTR_ERR(panel); dev_err(dev->dev, "failed to construct LCDC encoder\n");
dev_err(dev->dev, "failed to detect LVDS panel: %d\n", ret); return PTR_ERR(encoder);
goto fail;
} }
plane = mdp4_plane_init(dev, RGB2, true); /* LCDC can be hooked to DMA_P (TODO: Add DMA_S later?) */
if (IS_ERR(plane)) { encoder->possible_crtcs = 1 << DMA_P;
dev_err(dev->dev, "failed to construct plane for RGB2\n");
ret = PTR_ERR(plane);
goto fail;
}
crtc = mdp4_crtc_init(dev, plane, priv->num_crtcs, 0, DMA_P); connector = mdp4_lvds_connector_init(dev, panel_node, encoder);
if (IS_ERR(crtc)) { if (IS_ERR(connector)) {
dev_err(dev->dev, "failed to construct crtc for DMA_P\n"); dev_err(dev->dev, "failed to initialize LVDS connector\n");
ret = PTR_ERR(crtc); return PTR_ERR(connector);
goto fail;
} }
encoder = mdp4_lcdc_encoder_init(dev, panel); priv->encoders[priv->num_encoders++] = encoder;
priv->connectors[priv->num_connectors++] = connector;
break;
case DRM_MODE_ENCODER_TMDS:
encoder = mdp4_dtv_encoder_init(dev);
if (IS_ERR(encoder)) { if (IS_ERR(encoder)) {
dev_err(dev->dev, "failed to construct LCDC encoder\n"); dev_err(dev->dev, "failed to construct DTV encoder\n");
ret = PTR_ERR(encoder); return PTR_ERR(encoder);
goto fail;
} }
/* LCDC can be hooked to DMA_P: */ /* DTV can be hooked to DMA_E: */
encoder->possible_crtcs = 1 << priv->num_crtcs; encoder->possible_crtcs = 1 << 1;
if (priv->hdmi) {
/* Construct bridge/connector for HDMI: */
ret = hdmi_modeset_init(priv->hdmi, dev, encoder);
if (ret) {
dev_err(dev->dev, "failed to initialize HDMI: %d\n", ret);
return ret;
}
}
priv->crtcs[priv->num_crtcs++] = crtc;
priv->encoders[priv->num_encoders++] = encoder; priv->encoders[priv->num_encoders++] = encoder;
connector = mdp4_lvds_connector_init(dev, panel, encoder); break;
if (IS_ERR(connector)) { case DRM_MODE_ENCODER_DSI:
ret = PTR_ERR(connector); /* only DSI1 supported for now */
dev_err(dev->dev, "failed to initialize LVDS connector: %d\n", ret); dsi_id = 0;
goto fail;
if (!priv->dsi[dsi_id])
break;
for (i = 0; i < MSM_DSI_ENCODER_NUM; i++) {
dsi_encs[i] = mdp4_dsi_encoder_init(dev);
if (IS_ERR(dsi_encs[i])) {
ret = PTR_ERR(dsi_encs[i]);
dev_err(dev->dev,
"failed to construct DSI encoder: %d\n",
ret);
return ret;
} }
priv->connectors[priv->num_connectors++] = connector; /* TODO: Add DMA_S later? */
dsi_encs[i]->possible_crtcs = 1 << DMA_P;
priv->encoders[priv->num_encoders++] = dsi_encs[i];
}
/* ret = msm_dsi_modeset_init(priv->dsi[dsi_id], dev, dsi_encs);
* Setup DTV/HDMI path: RGB1 -> DMA_E -> DTV -> HDMI: if (ret) {
*/ dev_err(dev->dev, "failed to initialize DSI: %d\n",
ret);
return ret;
}
break;
default:
dev_err(dev->dev, "Invalid or unsupported interface\n");
return -EINVAL;
}
return 0;
}
static int modeset_init(struct mdp4_kms *mdp4_kms)
{
struct drm_device *dev = mdp4_kms->dev;
struct msm_drm_private *priv = dev->dev_private;
struct drm_plane *plane;
struct drm_crtc *crtc;
int i, ret;
static const enum mdp4_pipe rgb_planes[] = {
RGB1, RGB2,
};
static const enum mdp4_pipe vg_planes[] = {
VG1, VG2,
};
static const enum mdp4_dma mdp4_crtcs[] = {
DMA_P, DMA_E,
};
static const char * const mdp4_crtc_names[] = {
"DMA_P", "DMA_E",
};
static const int mdp4_intfs[] = {
DRM_MODE_ENCODER_LVDS,
DRM_MODE_ENCODER_DSI,
DRM_MODE_ENCODER_TMDS,
};
/* construct non-private planes: */
for (i = 0; i < ARRAY_SIZE(vg_planes); i++) {
plane = mdp4_plane_init(dev, vg_planes[i], false);
if (IS_ERR(plane)) {
dev_err(dev->dev,
"failed to construct plane for VG%d\n", i + 1);
ret = PTR_ERR(plane);
goto fail;
}
priv->planes[priv->num_planes++] = plane;
}
plane = mdp4_plane_init(dev, RGB1, true); for (i = 0; i < ARRAY_SIZE(mdp4_crtcs); i++) {
plane = mdp4_plane_init(dev, rgb_planes[i], true);
if (IS_ERR(plane)) { if (IS_ERR(plane)) {
dev_err(dev->dev, "failed to construct plane for RGB1\n"); dev_err(dev->dev,
"failed to construct plane for RGB%d\n", i + 1);
ret = PTR_ERR(plane); ret = PTR_ERR(plane);
goto fail; goto fail;
} }
crtc = mdp4_crtc_init(dev, plane, priv->num_crtcs, 1, DMA_E); crtc = mdp4_crtc_init(dev, plane, priv->num_crtcs, i,
mdp4_crtcs[i]);
if (IS_ERR(crtc)) { if (IS_ERR(crtc)) {
dev_err(dev->dev, "failed to construct crtc for DMA_E\n"); dev_err(dev->dev, "failed to construct crtc for %s\n",
mdp4_crtc_names[i]);
ret = PTR_ERR(crtc); ret = PTR_ERR(crtc);
goto fail; goto fail;
} }
encoder = mdp4_dtv_encoder_init(dev); priv->crtcs[priv->num_crtcs++] = crtc;
if (IS_ERR(encoder)) {
dev_err(dev->dev, "failed to construct DTV encoder\n");
ret = PTR_ERR(encoder);
goto fail;
} }
/* DTV can be hooked to DMA_E: */ /*
encoder->possible_crtcs = 1 << priv->num_crtcs; * we currently set up two relatively fixed paths:
*
priv->crtcs[priv->num_crtcs++] = crtc; * LCDC/LVDS path: RGB1 -> DMA_P -> LCDC -> LVDS
priv->encoders[priv->num_encoders++] = encoder; * or
* DSI path: RGB1 -> DMA_P -> DSI1 -> DSI Panel
*
* DTV/HDMI path: RGB2 -> DMA_E -> DTV -> HDMI
*/
if (priv->hdmi) { for (i = 0; i < ARRAY_SIZE(mdp4_intfs); i++) {
/* Construct bridge/connector for HDMI: */ ret = mdp4_modeset_init_intf(mdp4_kms, mdp4_intfs[i]);
ret = hdmi_modeset_init(priv->hdmi, dev, encoder);
if (ret) { if (ret) {
dev_err(dev->dev, "failed to initialize HDMI: %d\n", ret); dev_err(dev->dev, "failed to initialize intf: %d, %d\n",
i, ret);
goto fail; goto fail;
} }
} }
...@@ -558,17 +617,10 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev) ...@@ -558,17 +617,10 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev)
static struct mdp4_platform_config *mdp4_get_config(struct platform_device *dev) static struct mdp4_platform_config *mdp4_get_config(struct platform_device *dev)
{ {
static struct mdp4_platform_config config = {}; static struct mdp4_platform_config config = {};
#ifdef CONFIG_OF
/* TODO */ /* TODO: Chips that aren't apq8064 have a 200 Mhz max_clk */
config.max_clk = 266667000; config.max_clk = 266667000;
config.iommu = iommu_domain_alloc(&platform_bus_type); config.iommu = iommu_domain_alloc(&platform_bus_type);
#else
if (cpu_is_apq8064())
config.max_clk = 266667000;
else
config.max_clk = 200000000;
config.iommu = msm_get_iommu_domain(DISPLAY_READ_DOMAIN);
#endif
return &config; return &config;
} }
...@@ -157,7 +157,7 @@ static inline uint32_t mixercfg(uint32_t mixer_cfg, int mixer, ...@@ -157,7 +157,7 @@ static inline uint32_t mixercfg(uint32_t mixer_cfg, int mixer,
COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE6_MIXER1); COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE6_MIXER1);
break; break;
default: default:
WARN_ON("invalid pipe"); WARN(1, "invalid pipe");
break; break;
} }
...@@ -212,10 +212,19 @@ struct drm_encoder *mdp4_dtv_encoder_init(struct drm_device *dev); ...@@ -212,10 +212,19 @@ struct drm_encoder *mdp4_dtv_encoder_init(struct drm_device *dev);
long mdp4_lcdc_round_pixclk(struct drm_encoder *encoder, unsigned long rate); long mdp4_lcdc_round_pixclk(struct drm_encoder *encoder, unsigned long rate);
struct drm_encoder *mdp4_lcdc_encoder_init(struct drm_device *dev, struct drm_encoder *mdp4_lcdc_encoder_init(struct drm_device *dev,
struct drm_panel *panel); struct device_node *panel_node);
struct drm_connector *mdp4_lvds_connector_init(struct drm_device *dev, struct drm_connector *mdp4_lvds_connector_init(struct drm_device *dev,
struct drm_panel *panel, struct drm_encoder *encoder); struct device_node *panel_node, struct drm_encoder *encoder);
#ifdef CONFIG_DRM_MSM_DSI
struct drm_encoder *mdp4_dsi_encoder_init(struct drm_device *dev);
#else
static inline struct drm_encoder *mdp4_dsi_encoder_init(struct drm_device *dev)
{
return ERR_PTR(-ENODEV);
}
#endif
#ifdef CONFIG_COMMON_CLK #ifdef CONFIG_COMMON_CLK
struct clk *mpd4_lvds_pll_init(struct drm_device *dev); struct clk *mpd4_lvds_pll_init(struct drm_device *dev);
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
struct mdp4_lcdc_encoder { struct mdp4_lcdc_encoder {
struct drm_encoder base; struct drm_encoder base;
struct device_node *panel_node;
struct drm_panel *panel; struct drm_panel *panel;
struct clk *lcdc_clk; struct clk *lcdc_clk;
unsigned long int pixclock; unsigned long int pixclock;
...@@ -338,7 +339,7 @@ static void mdp4_lcdc_encoder_disable(struct drm_encoder *encoder) ...@@ -338,7 +339,7 @@ static void mdp4_lcdc_encoder_disable(struct drm_encoder *encoder)
struct mdp4_lcdc_encoder *mdp4_lcdc_encoder = struct mdp4_lcdc_encoder *mdp4_lcdc_encoder =
to_mdp4_lcdc_encoder(encoder); to_mdp4_lcdc_encoder(encoder);
struct mdp4_kms *mdp4_kms = get_kms(encoder); struct mdp4_kms *mdp4_kms = get_kms(encoder);
struct drm_panel *panel = mdp4_lcdc_encoder->panel; struct drm_panel *panel;
int i, ret; int i, ret;
if (WARN_ON(!mdp4_lcdc_encoder->enabled)) if (WARN_ON(!mdp4_lcdc_encoder->enabled))
...@@ -346,6 +347,7 @@ static void mdp4_lcdc_encoder_disable(struct drm_encoder *encoder) ...@@ -346,6 +347,7 @@ static void mdp4_lcdc_encoder_disable(struct drm_encoder *encoder)
mdp4_write(mdp4_kms, REG_MDP4_LCDC_ENABLE, 0); mdp4_write(mdp4_kms, REG_MDP4_LCDC_ENABLE, 0);
panel = of_drm_find_panel(mdp4_lcdc_encoder->panel_node);
if (panel) { if (panel) {
drm_panel_disable(panel); drm_panel_disable(panel);
drm_panel_unprepare(panel); drm_panel_unprepare(panel);
...@@ -381,7 +383,7 @@ static void mdp4_lcdc_encoder_enable(struct drm_encoder *encoder) ...@@ -381,7 +383,7 @@ static void mdp4_lcdc_encoder_enable(struct drm_encoder *encoder)
to_mdp4_lcdc_encoder(encoder); to_mdp4_lcdc_encoder(encoder);
unsigned long pc = mdp4_lcdc_encoder->pixclock; unsigned long pc = mdp4_lcdc_encoder->pixclock;
struct mdp4_kms *mdp4_kms = get_kms(encoder); struct mdp4_kms *mdp4_kms = get_kms(encoder);
struct drm_panel *panel = mdp4_lcdc_encoder->panel; struct drm_panel *panel;
int i, ret; int i, ret;
if (WARN_ON(mdp4_lcdc_encoder->enabled)) if (WARN_ON(mdp4_lcdc_encoder->enabled))
...@@ -414,6 +416,7 @@ static void mdp4_lcdc_encoder_enable(struct drm_encoder *encoder) ...@@ -414,6 +416,7 @@ static void mdp4_lcdc_encoder_enable(struct drm_encoder *encoder)
if (ret) if (ret)
dev_err(dev->dev, "failed to enable lcdc_clk: %d\n", ret); dev_err(dev->dev, "failed to enable lcdc_clk: %d\n", ret);
panel = of_drm_find_panel(mdp4_lcdc_encoder->panel_node);
if (panel) { if (panel) {
drm_panel_prepare(panel); drm_panel_prepare(panel);
drm_panel_enable(panel); drm_panel_enable(panel);
...@@ -442,7 +445,7 @@ long mdp4_lcdc_round_pixclk(struct drm_encoder *encoder, unsigned long rate) ...@@ -442,7 +445,7 @@ long mdp4_lcdc_round_pixclk(struct drm_encoder *encoder, unsigned long rate)
/* initialize encoder */ /* initialize encoder */
struct drm_encoder *mdp4_lcdc_encoder_init(struct drm_device *dev, struct drm_encoder *mdp4_lcdc_encoder_init(struct drm_device *dev,
struct drm_panel *panel) struct device_node *panel_node)
{ {
struct drm_encoder *encoder = NULL; struct drm_encoder *encoder = NULL;
struct mdp4_lcdc_encoder *mdp4_lcdc_encoder; struct mdp4_lcdc_encoder *mdp4_lcdc_encoder;
...@@ -455,7 +458,7 @@ struct drm_encoder *mdp4_lcdc_encoder_init(struct drm_device *dev, ...@@ -455,7 +458,7 @@ struct drm_encoder *mdp4_lcdc_encoder_init(struct drm_device *dev,
goto fail; goto fail;
} }
mdp4_lcdc_encoder->panel = panel; mdp4_lcdc_encoder->panel_node = panel_node;
encoder = &mdp4_lcdc_encoder->base; encoder = &mdp4_lcdc_encoder->base;
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
struct mdp4_lvds_connector { struct mdp4_lvds_connector {
struct drm_connector base; struct drm_connector base;
struct drm_encoder *encoder; struct drm_encoder *encoder;
struct device_node *panel_node;
struct drm_panel *panel; struct drm_panel *panel;
}; };
#define to_mdp4_lvds_connector(x) container_of(x, struct mdp4_lvds_connector, base) #define to_mdp4_lvds_connector(x) container_of(x, struct mdp4_lvds_connector, base)
...@@ -33,6 +34,10 @@ static enum drm_connector_status mdp4_lvds_connector_detect( ...@@ -33,6 +34,10 @@ static enum drm_connector_status mdp4_lvds_connector_detect(
struct mdp4_lvds_connector *mdp4_lvds_connector = struct mdp4_lvds_connector *mdp4_lvds_connector =
to_mdp4_lvds_connector(connector); to_mdp4_lvds_connector(connector);
if (!mdp4_lvds_connector->panel)
mdp4_lvds_connector->panel =
of_drm_find_panel(mdp4_lvds_connector->panel_node);
return mdp4_lvds_connector->panel ? return mdp4_lvds_connector->panel ?
connector_status_connected : connector_status_connected :
connector_status_disconnected; connector_status_disconnected;
...@@ -42,10 +47,6 @@ static void mdp4_lvds_connector_destroy(struct drm_connector *connector) ...@@ -42,10 +47,6 @@ static void mdp4_lvds_connector_destroy(struct drm_connector *connector)
{ {
struct mdp4_lvds_connector *mdp4_lvds_connector = struct mdp4_lvds_connector *mdp4_lvds_connector =
to_mdp4_lvds_connector(connector); to_mdp4_lvds_connector(connector);
struct drm_panel *panel = mdp4_lvds_connector->panel;
if (panel)
drm_panel_detach(panel);
drm_connector_unregister(connector); drm_connector_unregister(connector);
drm_connector_cleanup(connector); drm_connector_cleanup(connector);
...@@ -60,9 +61,14 @@ static int mdp4_lvds_connector_get_modes(struct drm_connector *connector) ...@@ -60,9 +61,14 @@ static int mdp4_lvds_connector_get_modes(struct drm_connector *connector)
struct drm_panel *panel = mdp4_lvds_connector->panel; struct drm_panel *panel = mdp4_lvds_connector->panel;
int ret = 0; int ret = 0;
if (panel) if (panel) {
drm_panel_attach(panel, connector);
ret = panel->funcs->get_modes(panel); ret = panel->funcs->get_modes(panel);
drm_panel_detach(panel);
}
return ret; return ret;
} }
...@@ -111,7 +117,7 @@ static const struct drm_connector_helper_funcs mdp4_lvds_connector_helper_funcs ...@@ -111,7 +117,7 @@ static const struct drm_connector_helper_funcs mdp4_lvds_connector_helper_funcs
/* initialize connector */ /* initialize connector */
struct drm_connector *mdp4_lvds_connector_init(struct drm_device *dev, struct drm_connector *mdp4_lvds_connector_init(struct drm_device *dev,
struct drm_panel *panel, struct drm_encoder *encoder) struct device_node *panel_node, struct drm_encoder *encoder)
{ {
struct drm_connector *connector = NULL; struct drm_connector *connector = NULL;
struct mdp4_lvds_connector *mdp4_lvds_connector; struct mdp4_lvds_connector *mdp4_lvds_connector;
...@@ -124,7 +130,7 @@ struct drm_connector *mdp4_lvds_connector_init(struct drm_device *dev, ...@@ -124,7 +130,7 @@ struct drm_connector *mdp4_lvds_connector_init(struct drm_device *dev,
} }
mdp4_lvds_connector->encoder = encoder; mdp4_lvds_connector->encoder = encoder;
mdp4_lvds_connector->panel = panel; mdp4_lvds_connector->panel_node = panel_node;
connector = &mdp4_lvds_connector->base; connector = &mdp4_lvds_connector->base;
...@@ -141,9 +147,6 @@ struct drm_connector *mdp4_lvds_connector_init(struct drm_device *dev, ...@@ -141,9 +147,6 @@ struct drm_connector *mdp4_lvds_connector_init(struct drm_device *dev,
drm_mode_connector_attach_encoder(connector, encoder); drm_mode_connector_attach_encoder(connector, encoder);
if (panel)
drm_panel_attach(panel, connector);
return connector; return connector;
fail: fail:
......
...@@ -553,9 +553,7 @@ struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms, ...@@ -553,9 +553,7 @@ struct mdp5_cfg_handler *mdp5_cfg_init(struct mdp5_kms *mdp5_kms,
static struct mdp5_cfg_platform *mdp5_get_config(struct platform_device *dev) static struct mdp5_cfg_platform *mdp5_get_config(struct platform_device *dev)
{ {
static struct mdp5_cfg_platform config = {}; static struct mdp5_cfg_platform config = {};
#ifdef CONFIG_OF
/* TODO */
#endif
config.iommu = iommu_domain_alloc(&platform_bus_type); config.iommu = iommu_domain_alloc(&platform_bus_type);
return &config; return &config;
......
...@@ -293,6 +293,24 @@ static const struct drm_encoder_helper_funcs mdp5_encoder_helper_funcs = { ...@@ -293,6 +293,24 @@ static const struct drm_encoder_helper_funcs mdp5_encoder_helper_funcs = {
.enable = mdp5_encoder_enable, .enable = mdp5_encoder_enable,
}; };
int mdp5_encoder_get_linecount(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.num;
return mdp5_read(mdp5_kms, REG_MDP5_INTF_LINE_COUNT(intf));
}
u32 mdp5_encoder_get_framecount(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.num;
return mdp5_read(mdp5_kms, REG_MDP5_INTF_FRAME_COUNT(intf));
}
int mdp5_encoder_set_split_display(struct drm_encoder *encoder, int mdp5_encoder_set_split_display(struct drm_encoder *encoder,
struct drm_encoder *slave_encoder) struct drm_encoder *slave_encoder)
{ {
......
...@@ -31,7 +31,7 @@ void mdp5_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask, ...@@ -31,7 +31,7 @@ void mdp5_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask,
static void mdp5_irq_error_handler(struct mdp_irq *irq, uint32_t irqstatus) static void mdp5_irq_error_handler(struct mdp_irq *irq, uint32_t irqstatus)
{ {
DRM_ERROR("errors: %08x\n", irqstatus); DRM_ERROR_RATELIMITED("errors: %08x\n", irqstatus);
} }
void mdp5_irq_preinstall(struct msm_kms *kms) void mdp5_irq_preinstall(struct msm_kms *kms)
......
...@@ -468,6 +468,127 @@ static int get_clk(struct platform_device *pdev, struct clk **clkp, ...@@ -468,6 +468,127 @@ static int get_clk(struct platform_device *pdev, struct clk **clkp,
return 0; return 0;
} }
static struct drm_encoder *get_encoder_from_crtc(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
struct drm_encoder *encoder;
drm_for_each_encoder(encoder, dev)
if (encoder->crtc == crtc)
return encoder;
return NULL;
}
static int mdp5_get_scanoutpos(struct drm_device *dev, unsigned int pipe,
unsigned int flags, int *vpos, int *hpos,
ktime_t *stime, ktime_t *etime,
const struct drm_display_mode *mode)
{
struct msm_drm_private *priv = dev->dev_private;
struct drm_crtc *crtc;
struct drm_encoder *encoder;
int line, vsw, vbp, vactive_start, vactive_end, vfp_end;
int ret = 0;
crtc = priv->crtcs[pipe];
if (!crtc) {
DRM_ERROR("Invalid crtc %d\n", pipe);
return 0;
}
encoder = get_encoder_from_crtc(crtc);
if (!encoder) {
DRM_ERROR("no encoder found for crtc %d\n", pipe);
return 0;
}
ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE;
vsw = mode->crtc_vsync_end - mode->crtc_vsync_start;
vbp = mode->crtc_vtotal - mode->crtc_vsync_end;
/*
* the line counter is 1 at the start of the VSYNC pulse and VTOTAL at
* the end of VFP. Translate the porch values relative to the line
* counter positions.
*/
vactive_start = vsw + vbp + 1;
vactive_end = vactive_start + mode->crtc_vdisplay;
/* last scan line before VSYNC */
vfp_end = mode->crtc_vtotal;
if (stime)
*stime = ktime_get();
line = mdp5_encoder_get_linecount(encoder);
if (line < vactive_start) {
line -= vactive_start;
ret |= DRM_SCANOUTPOS_IN_VBLANK;
} else if (line > vactive_end) {
line = line - vfp_end - vactive_start;
ret |= DRM_SCANOUTPOS_IN_VBLANK;
} else {
line -= vactive_start;
}
*vpos = line;
*hpos = 0;
if (etime)
*etime = ktime_get();
return ret;
}
static int mdp5_get_vblank_timestamp(struct drm_device *dev, unsigned int pipe,
int *max_error,
struct timeval *vblank_time,
unsigned flags)
{
struct msm_drm_private *priv = dev->dev_private;
struct drm_crtc *crtc;
if (pipe < 0 || pipe >= priv->num_crtcs) {
DRM_ERROR("Invalid crtc %d\n", pipe);
return -EINVAL;
}
crtc = priv->crtcs[pipe];
if (!crtc) {
DRM_ERROR("Invalid crtc %d\n", pipe);
return -EINVAL;
}
return drm_calc_vbltimestamp_from_scanoutpos(dev, pipe, max_error,
vblank_time, flags,
&crtc->mode);
}
static u32 mdp5_get_vblank_counter(struct drm_device *dev, unsigned int pipe)
{
struct msm_drm_private *priv = dev->dev_private;
struct drm_crtc *crtc;
struct drm_encoder *encoder;
if (pipe < 0 || pipe >= priv->num_crtcs)
return 0;
crtc = priv->crtcs[pipe];
if (!crtc)
return 0;
encoder = get_encoder_from_crtc(crtc);
if (!encoder)
return 0;
return mdp5_encoder_get_framecount(encoder);
}
struct msm_kms *mdp5_kms_init(struct drm_device *dev) struct msm_kms *mdp5_kms_init(struct drm_device *dev)
{ {
struct platform_device *pdev = dev->platformdev; struct platform_device *pdev = dev->platformdev;
...@@ -590,6 +711,8 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) ...@@ -590,6 +711,8 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
!config->hw->intf.base[i]) !config->hw->intf.base[i])
continue; continue;
mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(i), 0); mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(i), 0);
mdp5_write(mdp5_kms, REG_MDP5_INTF_FRAME_LINE_COUNT_EN(i), 0x3);
} }
mdp5_disable(mdp5_kms); mdp5_disable(mdp5_kms);
mdelay(16); mdelay(16);
...@@ -635,6 +758,12 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev) ...@@ -635,6 +758,12 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
dev->mode_config.max_width = config->hw->lm.max_width; dev->mode_config.max_width = config->hw->lm.max_width;
dev->mode_config.max_height = config->hw->lm.max_height; dev->mode_config.max_height = config->hw->lm.max_height;
dev->driver->get_vblank_timestamp = mdp5_get_vblank_timestamp;
dev->driver->get_scanout_position = mdp5_get_scanoutpos;
dev->driver->get_vblank_counter = mdp5_get_vblank_counter;
dev->max_vblank_count = 0xffffffff;
dev->vblank_disable_immediate = true;
return kms; return kms;
fail: fail:
......
...@@ -222,6 +222,8 @@ struct drm_encoder *mdp5_encoder_init(struct drm_device *dev, ...@@ -222,6 +222,8 @@ struct drm_encoder *mdp5_encoder_init(struct drm_device *dev,
struct mdp5_interface *intf, struct mdp5_ctl *ctl); struct mdp5_interface *intf, struct mdp5_ctl *ctl);
int mdp5_encoder_set_split_display(struct drm_encoder *encoder, int mdp5_encoder_set_split_display(struct drm_encoder *encoder,
struct drm_encoder *slave_encoder); struct drm_encoder *slave_encoder);
int mdp5_encoder_get_linecount(struct drm_encoder *encoder);
u32 mdp5_encoder_get_framecount(struct drm_encoder *encoder);
#ifdef CONFIG_DRM_MSM_DSI #ifdef CONFIG_DRM_MSM_DSI
struct drm_encoder *mdp5_cmd_encoder_init(struct drm_device *dev, struct drm_encoder *mdp5_cmd_encoder_init(struct drm_device *dev,
......
...@@ -237,20 +237,9 @@ static int msm_unload(struct drm_device *dev) ...@@ -237,20 +237,9 @@ static int msm_unload(struct drm_device *dev)
static int get_mdp_ver(struct platform_device *pdev) static int get_mdp_ver(struct platform_device *pdev)
{ {
#ifdef CONFIG_OF
static const struct of_device_id match_types[] = { {
.compatible = "qcom,mdss_mdp",
.data = (void *)5,
}, {
/* end node */
} };
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
const struct of_device_id *match;
match = of_match_node(match_types, dev->of_node); return (int) (unsigned long) of_device_get_match_data(dev);
if (match)
return (int)(unsigned long)match->data;
#endif
return 4;
} }
#include <linux/of_address.h> #include <linux/of_address.h>
...@@ -258,10 +247,10 @@ static int get_mdp_ver(struct platform_device *pdev) ...@@ -258,10 +247,10 @@ static int get_mdp_ver(struct platform_device *pdev)
static int msm_init_vram(struct drm_device *dev) static int msm_init_vram(struct drm_device *dev)
{ {
struct msm_drm_private *priv = dev->dev_private; struct msm_drm_private *priv = dev->dev_private;
struct device_node *node;
unsigned long size = 0; unsigned long size = 0;
int ret = 0; int ret = 0;
#ifdef CONFIG_OF
/* In the device-tree world, we could have a 'memory-region' /* In the device-tree world, we could have a 'memory-region'
* phandle, which gives us a link to our "vram". Allocating * phandle, which gives us a link to our "vram". Allocating
* is all nicely abstracted behind the dma api, but we need * is all nicely abstracted behind the dma api, but we need
...@@ -278,7 +267,6 @@ static int msm_init_vram(struct drm_device *dev) ...@@ -278,7 +267,6 @@ static int msm_init_vram(struct drm_device *dev)
* as corruption on screen before we have a chance to * as corruption on screen before we have a chance to
* load and do initial modeset) * load and do initial modeset)
*/ */
struct device_node *node;
node = of_parse_phandle(dev->dev->of_node, "memory-region", 0); node = of_parse_phandle(dev->dev->of_node, "memory-region", 0);
if (node) { if (node) {
...@@ -288,14 +276,12 @@ static int msm_init_vram(struct drm_device *dev) ...@@ -288,14 +276,12 @@ static int msm_init_vram(struct drm_device *dev)
return ret; return ret;
size = r.end - r.start; size = r.end - r.start;
DRM_INFO("using VRAM carveout: %lx@%pa\n", size, &r.start); DRM_INFO("using VRAM carveout: %lx@%pa\n", size, &r.start);
} else
#endif
/* if we have no IOMMU, then we need to use carveout allocator. /* if we have no IOMMU, then we need to use carveout allocator.
* Grab the entire CMA chunk carved out in early startup in * Grab the entire CMA chunk carved out in early startup in
* mach-msm: * mach-msm:
*/ */
if (!iommu_present(&platform_bus_type)) { } else if (!iommu_present(&platform_bus_type)) {
DRM_INFO("using %s VRAM carveout\n", vram); DRM_INFO("using %s VRAM carveout\n", vram);
size = memparse(vram, NULL); size = memparse(vram, NULL);
} }
...@@ -1035,9 +1021,9 @@ static const struct dev_pm_ops msm_pm_ops = { ...@@ -1035,9 +1021,9 @@ static const struct dev_pm_ops msm_pm_ops = {
* Componentized driver support: * Componentized driver support:
*/ */
#ifdef CONFIG_OF /*
/* NOTE: the CONFIG_OF case duplicates the same code as exynos or imx * NOTE: duplication of the same code as exynos or imx (or probably any other).
* (or probably any other).. so probably some room for some helpers * so probably some room for some helpers
*/ */
static int compare_of(struct device *dev, void *data) static int compare_of(struct device *dev, void *data)
{ {
...@@ -1062,12 +1048,6 @@ static int add_components(struct device *dev, struct component_match **matchptr, ...@@ -1062,12 +1048,6 @@ static int add_components(struct device *dev, struct component_match **matchptr,
return 0; return 0;
} }
#else
static int compare_dev(struct device *dev, void *data)
{
return dev == data;
}
#endif
static int msm_drm_bind(struct device *dev) static int msm_drm_bind(struct device *dev)
{ {
...@@ -1091,35 +1071,9 @@ static const struct component_master_ops msm_drm_ops = { ...@@ -1091,35 +1071,9 @@ static const struct component_master_ops msm_drm_ops = {
static int msm_pdev_probe(struct platform_device *pdev) static int msm_pdev_probe(struct platform_device *pdev)
{ {
struct component_match *match = NULL; struct component_match *match = NULL;
#ifdef CONFIG_OF
add_components(&pdev->dev, &match, "connectors"); add_components(&pdev->dev, &match, "connectors");
add_components(&pdev->dev, &match, "gpus"); add_components(&pdev->dev, &match, "gpus");
#else
/* For non-DT case, it kinda sucks. We don't actually have a way
* to know whether or not we are waiting for certain devices (or if
* they are simply not present). But for non-DT we only need to
* care about apq8064/apq8060/etc (all mdp4/a3xx):
*/
static const char *devnames[] = {
"hdmi_msm.0", "kgsl-3d0.0",
};
int i;
DBG("Adding components..");
for (i = 0; i < ARRAY_SIZE(devnames); i++) {
struct device *dev;
dev = bus_find_device_by_name(&platform_bus_type,
NULL, devnames[i]);
if (!dev) {
dev_info(&pdev->dev, "still waiting for %s\n", devnames[i]);
return -EPROBE_DEFER;
}
component_match_add(&pdev->dev, &match, compare_dev, dev);
}
#endif
pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
return component_master_add_with_match(&pdev->dev, &msm_drm_ops, match); return component_master_add_with_match(&pdev->dev, &msm_drm_ops, match);
...@@ -1138,8 +1092,10 @@ static const struct platform_device_id msm_id[] = { ...@@ -1138,8 +1092,10 @@ static const struct platform_device_id msm_id[] = {
}; };
static const struct of_device_id dt_match[] = { static const struct of_device_id dt_match[] = {
{ .compatible = "qcom,mdp" }, /* mdp4 */ { .compatible = "qcom,mdp4", .data = (void *) 4 }, /* mdp4 */
{ .compatible = "qcom,mdss_mdp" }, /* mdp5 */ { .compatible = "qcom,mdp5", .data = (void *) 5 }, /* mdp5 */
/* to support downstream DT files */
{ .compatible = "qcom,mdss_mdp", .data = (void *) 5 }, /* mdp5 */
{} {}
}; };
MODULE_DEVICE_TABLE(of, dt_match); MODULE_DEVICE_TABLE(of, dt_match);
......
...@@ -31,14 +31,9 @@ ...@@ -31,14 +31,9 @@
#include <linux/iommu.h> #include <linux/iommu.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/of_graph.h> #include <linux/of_graph.h>
#include <linux/of_device.h>
#include <asm/sizes.h> #include <asm/sizes.h>
#ifndef CONFIG_OF
#include <mach/board.h>
#include <mach/socinfo.h>
#include <mach/iommu_domains.h>
#endif
#include <drm/drmP.h> #include <drm/drmP.h>
#include <drm/drm_atomic.h> #include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h> #include <drm/drm_atomic_helper.h>
......
...@@ -121,7 +121,7 @@ static int msm_fbdev_create(struct drm_fb_helper *helper, ...@@ -121,7 +121,7 @@ static int msm_fbdev_create(struct drm_fb_helper *helper,
/* note: if fb creation failed, we can't rely on fb destroy /* note: if fb creation failed, we can't rely on fb destroy
* to unref the bo: * to unref the bo:
*/ */
drm_gem_object_unreference(fbdev->bo); drm_gem_object_unreference_unlocked(fbdev->bo);
ret = PTR_ERR(fb); ret = PTR_ERR(fb);
goto fail; goto fail;
} }
......
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