提交 c4d922b1 编写于 作者: D Dave Airlie

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

 1) add LVDS support for mdp4 (tested with auo B101XTN01.0 panel)
 2) add B101XTN01.0 panel
 3) bit of gpu refactoring to prepare for addition of addition gpu
generations beyond just a3xx

* 'msm-next' of git://people.freedesktop.org/~robclark/linux:
  drm/msm/adreno: push dump/show stuff to base class
  drm/msm/adreno: bit of init refactoring
  drm/msm/adreno: move decision about what gpu to to load
  drm/msm/adreno: split adreno device out into it's own file
  drm/panel/simple: add optronics B101XTN01.0 (v3)
  drm/msm/mdp4: add LVDS panel support
  drm/msm/mdp4: fix blend setup with multiple crtcs
  drm/msm: update generated headers
AU Optronics Corporation 10.1" WXGA TFT LCD panel
Required properties:
- compatible: should be "auo,b101xtn01"
This binding is compatible with the simple-panel binding, which is specified
in simple-panel.txt in this directory.
......@@ -4,6 +4,7 @@ config DRM_MSM
depends on DRM
depends on ARCH_QCOM || (ARM && COMPILE_TEST)
select DRM_KMS_HELPER
select DRM_PANEL
select SHMEM
select TMPFS
default y
......
......@@ -4,6 +4,7 @@ ifeq (, $(findstring -W,$(EXTRA_CFLAGS)))
endif
msm-y := \
adreno/adreno_device.o \
adreno/adreno_gpu.o \
adreno/a3xx_gpu.o \
hdmi/hdmi.o \
......@@ -18,6 +19,8 @@ msm-y := \
mdp/mdp_kms.o \
mdp/mdp4/mdp4_crtc.o \
mdp/mdp4/mdp4_dtv_encoder.o \
mdp/mdp4/mdp4_lcdc_encoder.o \
mdp/mdp4/mdp4_lvds_connector.o \
mdp/mdp4/mdp4_irq.o \
mdp/mdp4/mdp4_kms.o \
mdp/mdp4/mdp4_plane.o \
......@@ -39,5 +42,6 @@ msm-y := \
msm_ringbuffer.o
msm-$(CONFIG_DRM_MSM_FBDEV) += msm_fbdev.o
msm-$(CONFIG_COMMON_CLK) += mdp/mdp4/mdp4_lvds_pll.o
obj-$(CONFIG_DRM_MSM) += msm.o
......@@ -12,9 +12,9 @@ The rules-ng-ng source files this header was generated from are:
- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml ( 32901 bytes, from 2014-06-02 15:21:30)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 9859 bytes, from 2014-06-02 15:21:30)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 14477 bytes, from 2014-05-16 11:51:57)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 58020 bytes, from 2014-06-25 12:57:16)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 26602 bytes, from 2014-06-25 12:57:16)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 14960 bytes, from 2014-07-27 17:22:13)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 58020 bytes, from 2014-08-01 12:22:48)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 41068 bytes, from 2014-08-01 12:22:48)
Copyright (C) 2013-2014 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)
......
......@@ -12,9 +12,9 @@ The rules-ng-ng source files this header was generated from are:
- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml ( 32901 bytes, from 2014-06-02 15:21:30)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 9859 bytes, from 2014-06-02 15:21:30)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 14477 bytes, from 2014-05-16 11:51:57)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 58020 bytes, from 2014-06-25 12:57:16)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 26602 bytes, from 2014-06-25 12:57:16)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 14960 bytes, from 2014-07-27 17:22:13)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 58020 bytes, from 2014-08-01 12:22:48)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 41068 bytes, from 2014-08-01 12:22:48)
Copyright (C) 2013-2014 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)
......@@ -654,7 +654,7 @@ static inline uint32_t A3XX_GRAS_SU_POINT_SIZE(float val)
#define A3XX_GRAS_SU_POLY_OFFSET_SCALE_VAL__SHIFT 0
static inline uint32_t A3XX_GRAS_SU_POLY_OFFSET_SCALE_VAL(float val)
{
return ((((uint32_t)(val * 40.0))) << A3XX_GRAS_SU_POLY_OFFSET_SCALE_VAL__SHIFT) & A3XX_GRAS_SU_POLY_OFFSET_SCALE_VAL__MASK;
return ((((uint32_t)(val * 28.0))) << A3XX_GRAS_SU_POLY_OFFSET_SCALE_VAL__SHIFT) & A3XX_GRAS_SU_POLY_OFFSET_SCALE_VAL__MASK;
}
#define REG_A3XX_GRAS_SU_POLY_OFFSET_OFFSET 0x0000206d
......@@ -662,7 +662,7 @@ static inline uint32_t A3XX_GRAS_SU_POLY_OFFSET_SCALE_VAL(float val)
#define A3XX_GRAS_SU_POLY_OFFSET_OFFSET__SHIFT 0
static inline uint32_t A3XX_GRAS_SU_POLY_OFFSET_OFFSET(float val)
{
return ((((uint32_t)(val * 44.0))) << A3XX_GRAS_SU_POLY_OFFSET_OFFSET__SHIFT) & A3XX_GRAS_SU_POLY_OFFSET_OFFSET__MASK;
return ((((uint32_t)(val * 28.0))) << A3XX_GRAS_SU_POLY_OFFSET_OFFSET__SHIFT) & A3XX_GRAS_SU_POLY_OFFSET_OFFSET__MASK;
}
#define REG_A3XX_GRAS_SU_MODE_CONTROL 0x00002070
......@@ -1696,7 +1696,7 @@ static inline uint32_t A3XX_SP_VS_CTRL_REG1_CONSTFOOTPRINT(uint32_t val)
{
return ((val) << A3XX_SP_VS_CTRL_REG1_CONSTFOOTPRINT__SHIFT) & A3XX_SP_VS_CTRL_REG1_CONSTFOOTPRINT__MASK;
}
#define A3XX_SP_VS_CTRL_REG1_INITIALOUTSTANDING__MASK 0x3f000000
#define A3XX_SP_VS_CTRL_REG1_INITIALOUTSTANDING__MASK 0x7f000000
#define A3XX_SP_VS_CTRL_REG1_INITIALOUTSTANDING__SHIFT 24
static inline uint32_t A3XX_SP_VS_CTRL_REG1_INITIALOUTSTANDING(uint32_t val)
{
......
......@@ -35,10 +35,8 @@
A3XX_INT0_CP_AHB_ERROR_HALT | \
A3XX_INT0_UCHE_OOB_ACCESS)
extern bool hang_debug;
static bool hang_debug = false;
MODULE_PARM_DESC(hang_debug, "Dump registers when hang is detected (can be slow!)");
module_param_named(hang_debug, hang_debug, bool, 0600);
static void a3xx_dump(struct msm_gpu *gpu);
static void a3xx_me_init(struct msm_gpu *gpu)
......@@ -387,58 +385,26 @@ static const unsigned int a3xx_registers[] = {
0x2750, 0x2756, 0x2760, 0x2760, 0x300c, 0x300e, 0x301c, 0x301d,
0x302a, 0x302a, 0x302c, 0x302d, 0x3030, 0x3031, 0x3034, 0x3036,
0x303c, 0x303c, 0x305e, 0x305f,
~0 /* sentinel */
};
#ifdef CONFIG_DEBUG_FS
static void a3xx_show(struct msm_gpu *gpu, struct seq_file *m)
{
int i;
adreno_show(gpu, m);
gpu->funcs->pm_resume(gpu);
seq_printf(m, "status: %08x\n",
gpu_read(gpu, REG_A3XX_RBBM_STATUS));
/* dump these out in a form that can be parsed by demsm: */
seq_printf(m, "IO:region %s 00000000 00020000\n", gpu->name);
for (i = 0; i < ARRAY_SIZE(a3xx_registers); i += 2) {
uint32_t start = a3xx_registers[i];
uint32_t end = a3xx_registers[i+1];
uint32_t addr;
for (addr = start; addr <= end; addr++) {
uint32_t val = gpu_read(gpu, addr);
seq_printf(m, "IO:R %08x %08x\n", addr<<2, val);
}
}
gpu->funcs->pm_suspend(gpu);
adreno_show(gpu, m);
}
#endif
/* would be nice to not have to duplicate the _show() stuff with printk(): */
static void a3xx_dump(struct msm_gpu *gpu)
{
int i;
adreno_dump(gpu);
printk("status: %08x\n",
gpu_read(gpu, REG_A3XX_RBBM_STATUS));
/* dump these out in a form that can be parsed by demsm: */
printk("IO:region %s 00000000 00020000\n", gpu->name);
for (i = 0; i < ARRAY_SIZE(a3xx_registers); i += 2) {
uint32_t start = a3xx_registers[i];
uint32_t end = a3xx_registers[i+1];
uint32_t addr;
for (addr = start; addr <= end; addr++) {
uint32_t val = gpu_read(gpu, addr);
printk("IO:R %08x %08x\n", addr<<2, val);
}
}
adreno_dump(gpu);
}
static const struct adreno_gpu_funcs funcs = {
......@@ -474,7 +440,6 @@ struct msm_gpu *a3xx_gpu_init(struct drm_device *dev)
struct msm_gpu *gpu;
struct msm_drm_private *priv = dev->dev_private;
struct platform_device *pdev = priv->gpu_pdev;
struct adreno_platform_config *config;
int ret;
if (!pdev) {
......@@ -483,8 +448,6 @@ struct msm_gpu *a3xx_gpu_init(struct drm_device *dev)
goto fail;
}
config = pdev->dev.platform_data;
a3xx_gpu = kzalloc(sizeof(*a3xx_gpu), GFP_KERNEL);
if (!a3xx_gpu) {
ret = -ENOMEM;
......@@ -496,20 +459,12 @@ struct msm_gpu *a3xx_gpu_init(struct drm_device *dev)
a3xx_gpu->pdev = pdev;
gpu->fast_rate = config->fast_rate;
gpu->slow_rate = config->slow_rate;
gpu->bus_freq = config->bus_freq;
#ifdef CONFIG_MSM_BUS_SCALING
gpu->bus_scale_table = config->bus_scale_table;
#endif
DBG("fast_rate=%u, slow_rate=%u, bus_freq=%u",
gpu->fast_rate, gpu->slow_rate, gpu->bus_freq);
gpu->perfcntrs = perfcntrs;
gpu->num_perfcntrs = ARRAY_SIZE(perfcntrs);
ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, config->rev);
adreno_gpu->registers = a3xx_registers;
ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs);
if (ret)
goto fail;
......@@ -549,158 +504,3 @@ struct msm_gpu *a3xx_gpu_init(struct drm_device *dev)
return ERR_PTR(ret);
}
/*
* The a3xx device:
*/
#if defined(CONFIG_MSM_BUS_SCALING) && !defined(CONFIG_OF)
# include <mach/kgsl.h>
#endif
static void set_gpu_pdev(struct drm_device *dev,
struct platform_device *pdev)
{
struct msm_drm_private *priv = dev->dev_private;
priv->gpu_pdev = pdev;
}
static int a3xx_bind(struct device *dev, struct device *master, void *data)
{
static struct adreno_platform_config config = {};
#ifdef CONFIG_OF
struct device_node *child, *node = dev->of_node;
u32 val;
int ret;
ret = of_property_read_u32(node, "qcom,chipid", &val);
if (ret) {
dev_err(dev, "could not find chipid: %d\n", ret);
return ret;
}
config.rev = ADRENO_REV((val >> 24) & 0xff,
(val >> 16) & 0xff, (val >> 8) & 0xff, val & 0xff);
/* find clock rates: */
config.fast_rate = 0;
config.slow_rate = ~0;
for_each_child_of_node(node, child) {
if (of_device_is_compatible(child, "qcom,gpu-pwrlevels")) {
struct device_node *pwrlvl;
for_each_child_of_node(child, pwrlvl) {
ret = of_property_read_u32(pwrlvl, "qcom,gpu-freq", &val);
if (ret) {
dev_err(dev, "could not find gpu-freq: %d\n", ret);
return ret;
}
config.fast_rate = max(config.fast_rate, val);
config.slow_rate = min(config.slow_rate, val);
}
}
}
if (!config.fast_rate) {
dev_err(dev, "could not find clk rates\n");
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 CONFIG_MSM_BUS_SCALING
config.bus_scale_table = pdata->bus_scale_table;
# endif
#endif
dev->platform_data = &config;
set_gpu_pdev(dev_get_drvdata(master), to_platform_device(dev));
return 0;
}
static void a3xx_unbind(struct device *dev, struct device *master,
void *data)
{
set_gpu_pdev(dev_get_drvdata(master), NULL);
}
static const struct component_ops a3xx_ops = {
.bind = a3xx_bind,
.unbind = a3xx_unbind,
};
static int a3xx_probe(struct platform_device *pdev)
{
return component_add(&pdev->dev, &a3xx_ops);
}
static int a3xx_remove(struct platform_device *pdev)
{
component_del(&pdev->dev, &a3xx_ops);
return 0;
}
static const struct of_device_id dt_match[] = {
{ .compatible = "qcom,adreno-3xx" },
/* for backwards compat w/ downstream kgsl DT files: */
{ .compatible = "qcom,kgsl-3d0" },
{}
};
static struct platform_driver a3xx_driver = {
.probe = a3xx_probe,
.remove = a3xx_remove,
.driver = {
.name = "kgsl-3d0",
.of_match_table = dt_match,
},
};
void __init a3xx_register(void)
{
platform_driver_register(&a3xx_driver);
}
void __exit a3xx_unregister(void)
{
platform_driver_unregister(&a3xx_driver);
}
......@@ -12,9 +12,9 @@ The rules-ng-ng source files this header was generated from are:
- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml ( 32901 bytes, from 2014-06-02 15:21:30)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 9859 bytes, from 2014-06-02 15:21:30)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 14477 bytes, from 2014-05-16 11:51:57)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 58020 bytes, from 2014-06-25 12:57:16)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 26602 bytes, from 2014-06-25 12:57:16)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 14960 bytes, from 2014-07-27 17:22:13)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 58020 bytes, from 2014-08-01 12:22:48)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 41068 bytes, from 2014-08-01 12:22:48)
Copyright (C) 2013-2014 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)
......
/*
* Copyright (C) 2013-2014 Red Hat
* Author: Rob Clark <robdclark@gmail.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 "adreno_gpu.h"
#if defined(CONFIG_MSM_BUS_SCALING) && !defined(CONFIG_OF)
# include <mach/kgsl.h>
#endif
#define ANY_ID 0xff
bool hang_debug = false;
MODULE_PARM_DESC(hang_debug, "Dump registers when hang is detected (can be slow!)");
module_param_named(hang_debug, hang_debug, bool, 0600);
struct msm_gpu *a3xx_gpu_init(struct drm_device *dev);
static const struct adreno_info gpulist[] = {
{
.rev = ADRENO_REV(3, 0, 5, ANY_ID),
.revn = 305,
.name = "A305",
.pm4fw = "a300_pm4.fw",
.pfpfw = "a300_pfp.fw",
.gmem = SZ_256K,
.init = a3xx_gpu_init,
}, {
.rev = ADRENO_REV(3, 2, ANY_ID, ANY_ID),
.revn = 320,
.name = "A320",
.pm4fw = "a300_pm4.fw",
.pfpfw = "a300_pfp.fw",
.gmem = SZ_512K,
.init = a3xx_gpu_init,
}, {
.rev = ADRENO_REV(3, 3, 0, ANY_ID),
.revn = 330,
.name = "A330",
.pm4fw = "a330_pm4.fw",
.pfpfw = "a330_pfp.fw",
.gmem = SZ_1M,
.init = a3xx_gpu_init,
},
};
MODULE_FIRMWARE("a300_pm4.fw");
MODULE_FIRMWARE("a300_pfp.fw");
MODULE_FIRMWARE("a330_pm4.fw");
MODULE_FIRMWARE("a330_pfp.fw");
static inline bool _rev_match(uint8_t entry, uint8_t id)
{
return (entry == ANY_ID) || (entry == id);
}
const struct adreno_info *adreno_info(struct adreno_rev rev)
{
int i;
/* identify gpu: */
for (i = 0; i < ARRAY_SIZE(gpulist); i++) {
const struct adreno_info *info = &gpulist[i];
if (_rev_match(info->rev.core, rev.core) &&
_rev_match(info->rev.major, rev.major) &&
_rev_match(info->rev.minor, rev.minor) &&
_rev_match(info->rev.patchid, rev.patchid))
return info;
}
return NULL;
}
struct msm_gpu *adreno_load_gpu(struct drm_device *dev)
{
struct msm_drm_private *priv = dev->dev_private;
struct platform_device *pdev = priv->gpu_pdev;
struct adreno_platform_config *config;
struct adreno_rev rev;
const struct adreno_info *info;
struct msm_gpu *gpu = NULL;
if (!pdev) {
dev_err(dev->dev, "no adreno device\n");
return NULL;
}
config = pdev->dev.platform_data;
rev = config->rev;
info = adreno_info(config->rev);
if (!info) {
dev_warn(dev->dev, "Unknown GPU revision: %u.%u.%u.%u\n",
rev.core, rev.major, rev.minor, rev.patchid);
return NULL;
}
DBG("Found GPU: %u.%u.%u.%u", rev.core, rev.major,
rev.minor, rev.patchid);
gpu = info->init(dev);
if (IS_ERR(gpu)) {
dev_warn(dev->dev, "failed to load adreno gpu\n");
gpu = NULL;
/* not fatal */
}
if (gpu) {
int ret;
mutex_lock(&dev->struct_mutex);
gpu->funcs->pm_resume(gpu);
mutex_unlock(&dev->struct_mutex);
ret = gpu->funcs->hw_init(gpu);
if (ret) {
dev_err(dev->dev, "gpu hw init failed: %d\n", ret);
gpu->funcs->destroy(gpu);
gpu = NULL;
} else {
/* give inactive pm a chance to kick in: */
msm_gpu_retire(gpu);
}
}
return gpu;
}
static void set_gpu_pdev(struct drm_device *dev,
struct platform_device *pdev)
{
struct msm_drm_private *priv = dev->dev_private;
priv->gpu_pdev = pdev;
}
static int adreno_bind(struct device *dev, struct device *master, void *data)
{
static struct adreno_platform_config config = {};
#ifdef CONFIG_OF
struct device_node *child, *node = dev->of_node;
u32 val;
int ret;
ret = of_property_read_u32(node, "qcom,chipid", &val);
if (ret) {
dev_err(dev, "could not find chipid: %d\n", ret);
return ret;
}
config.rev = ADRENO_REV((val >> 24) & 0xff,
(val >> 16) & 0xff, (val >> 8) & 0xff, val & 0xff);
/* find clock rates: */
config.fast_rate = 0;
config.slow_rate = ~0;
for_each_child_of_node(node, child) {
if (of_device_is_compatible(child, "qcom,gpu-pwrlevels")) {
struct device_node *pwrlvl;
for_each_child_of_node(child, pwrlvl) {
ret = of_property_read_u32(pwrlvl, "qcom,gpu-freq", &val);
if (ret) {
dev_err(dev, "could not find gpu-freq: %d\n", ret);
return ret;
}
config.fast_rate = max(config.fast_rate, val);
config.slow_rate = min(config.slow_rate, val);
}
}
}
if (!config.fast_rate) {
dev_err(dev, "could not find clk rates\n");
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 CONFIG_MSM_BUS_SCALING
config.bus_scale_table = pdata->bus_scale_table;
# endif
#endif
dev->platform_data = &config;
set_gpu_pdev(dev_get_drvdata(master), to_platform_device(dev));
return 0;
}
static void adreno_unbind(struct device *dev, struct device *master,
void *data)
{
set_gpu_pdev(dev_get_drvdata(master), NULL);
}
static const struct component_ops a3xx_ops = {
.bind = adreno_bind,
.unbind = adreno_unbind,
};
static int adreno_probe(struct platform_device *pdev)
{
return component_add(&pdev->dev, &a3xx_ops);
}
static int adreno_remove(struct platform_device *pdev)
{
component_del(&pdev->dev, &a3xx_ops);
return 0;
}
static const struct of_device_id dt_match[] = {
{ .compatible = "qcom,adreno-3xx" },
/* for backwards compat w/ downstream kgsl DT files: */
{ .compatible = "qcom,kgsl-3d0" },
{}
};
static struct platform_driver adreno_driver = {
.probe = adreno_probe,
.remove = adreno_remove,
.driver = {
.name = "adreno",
.of_match_table = dt_match,
},
};
void __init adreno_register(void)
{
platform_driver_register(&adreno_driver);
}
void __exit adreno_unregister(void)
{
platform_driver_unregister(&adreno_driver);
}
......@@ -19,46 +19,6 @@
#include "msm_gem.h"
#include "msm_mmu.h"
struct adreno_info {
struct adreno_rev rev;
uint32_t revn;
const char *name;
const char *pm4fw, *pfpfw;
uint32_t gmem;
};
#define ANY_ID 0xff
static const struct adreno_info gpulist[] = {
{
.rev = ADRENO_REV(3, 0, 5, ANY_ID),
.revn = 305,
.name = "A305",
.pm4fw = "a300_pm4.fw",
.pfpfw = "a300_pfp.fw",
.gmem = SZ_256K,
}, {
.rev = ADRENO_REV(3, 2, ANY_ID, ANY_ID),
.revn = 320,
.name = "A320",
.pm4fw = "a300_pm4.fw",
.pfpfw = "a300_pfp.fw",
.gmem = SZ_512K,
}, {
.rev = ADRENO_REV(3, 3, 0, ANY_ID),
.revn = 330,
.name = "A330",
.pm4fw = "a330_pm4.fw",
.pfpfw = "a330_pfp.fw",
.gmem = SZ_1M,
},
};
MODULE_FIRMWARE("a300_pm4.fw");
MODULE_FIRMWARE("a300_pfp.fw");
MODULE_FIRMWARE("a330_pm4.fw");
MODULE_FIRMWARE("a330_pfp.fw");
#define RB_SIZE SZ_32K
#define RB_BLKSIZE 16
......@@ -252,6 +212,7 @@ void adreno_idle(struct msm_gpu *gpu)
void adreno_show(struct msm_gpu *gpu, struct seq_file *m)
{
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
int i;
seq_printf(m, "revision: %d (%d.%d.%d.%d)\n",
adreno_gpu->info->revn, adreno_gpu->rev.core,
......@@ -263,6 +224,23 @@ void adreno_show(struct msm_gpu *gpu, struct seq_file *m)
seq_printf(m, "rptr: %d\n", adreno_gpu->memptrs->rptr);
seq_printf(m, "wptr: %d\n", adreno_gpu->memptrs->wptr);
seq_printf(m, "rb wptr: %d\n", get_wptr(gpu->rb));
gpu->funcs->pm_resume(gpu);
/* dump these out in a form that can be parsed by demsm: */
seq_printf(m, "IO:region %s 00000000 00020000\n", gpu->name);
for (i = 0; adreno_gpu->registers[i] != ~0; i += 2) {
uint32_t start = adreno_gpu->registers[i];
uint32_t end = adreno_gpu->registers[i+1];
uint32_t addr;
for (addr = start; addr <= end; addr++) {
uint32_t val = gpu_read(gpu, addr);
seq_printf(m, "IO:R %08x %08x\n", addr<<2, val);
}
}
gpu->funcs->pm_suspend(gpu);
}
#endif
......@@ -270,6 +248,7 @@ void adreno_show(struct msm_gpu *gpu, struct seq_file *m)
void adreno_dump(struct msm_gpu *gpu)
{
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
int i;
printk("revision: %d (%d.%d.%d.%d)\n",
adreno_gpu->info->revn, adreno_gpu->rev.core,
......@@ -282,6 +261,18 @@ void adreno_dump(struct msm_gpu *gpu)
printk("wptr: %d\n", adreno_gpu->memptrs->wptr);
printk("rb wptr: %d\n", get_wptr(gpu->rb));
/* dump these out in a form that can be parsed by demsm: */
printk("IO:region %s 00000000 00020000\n", gpu->name);
for (i = 0; adreno_gpu->registers[i] != ~0; i += 2) {
uint32_t start = adreno_gpu->registers[i];
uint32_t end = adreno_gpu->registers[i+1];
uint32_t addr;
for (addr = start; addr <= end; addr++) {
uint32_t val = gpu_read(gpu, addr);
printk("IO:R %08x %08x\n", addr<<2, val);
}
}
}
static uint32_t ring_freewords(struct msm_gpu *gpu)
......@@ -304,65 +295,51 @@ static const char *iommu_ports[] = {
"gfx3d1_user", "gfx3d1_priv",
};
static inline bool _rev_match(uint8_t entry, uint8_t id)
{
return (entry == ANY_ID) || (entry == id);
}
int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
struct adreno_gpu *gpu, const struct adreno_gpu_funcs *funcs,
struct adreno_rev rev)
struct adreno_gpu *adreno_gpu, const struct adreno_gpu_funcs *funcs)
{
struct adreno_platform_config *config = pdev->dev.platform_data;
struct msm_gpu *gpu = &adreno_gpu->base;
struct msm_mmu *mmu;
int i, ret;
/* identify gpu: */
for (i = 0; i < ARRAY_SIZE(gpulist); i++) {
const struct adreno_info *info = &gpulist[i];
if (_rev_match(info->rev.core, rev.core) &&
_rev_match(info->rev.major, rev.major) &&
_rev_match(info->rev.minor, rev.minor) &&
_rev_match(info->rev.patchid, rev.patchid)) {
gpu->info = info;
gpu->revn = info->revn;
break;
}
}
if (i == ARRAY_SIZE(gpulist)) {
dev_err(drm->dev, "Unknown GPU revision: %u.%u.%u.%u\n",
rev.core, rev.major, rev.minor, rev.patchid);
return -ENXIO;
}
int ret;
DBG("Found GPU: %s (%u.%u.%u.%u)", gpu->info->name,
rev.core, rev.major, rev.minor, rev.patchid);
adreno_gpu->funcs = funcs;
adreno_gpu->info = adreno_info(config->rev);
adreno_gpu->gmem = adreno_gpu->info->gmem;
adreno_gpu->revn = adreno_gpu->info->revn;
adreno_gpu->rev = config->rev;
gpu->fast_rate = config->fast_rate;
gpu->slow_rate = config->slow_rate;
gpu->bus_freq = config->bus_freq;
#ifdef CONFIG_MSM_BUS_SCALING
gpu->bus_scale_table = config->bus_scale_table;
#endif
gpu->funcs = funcs;
gpu->gmem = gpu->info->gmem;
gpu->rev = rev;
DBG("fast_rate=%u, slow_rate=%u, bus_freq=%u",
gpu->fast_rate, gpu->slow_rate, gpu->bus_freq);
ret = request_firmware(&gpu->pm4, gpu->info->pm4fw, drm->dev);
ret = request_firmware(&adreno_gpu->pm4, adreno_gpu->info->pm4fw, drm->dev);
if (ret) {
dev_err(drm->dev, "failed to load %s PM4 firmware: %d\n",
gpu->info->pm4fw, ret);
adreno_gpu->info->pm4fw, ret);
return ret;
}
ret = request_firmware(&gpu->pfp, gpu->info->pfpfw, drm->dev);
ret = request_firmware(&adreno_gpu->pfp, adreno_gpu->info->pfpfw, drm->dev);
if (ret) {
dev_err(drm->dev, "failed to load %s PFP firmware: %d\n",
gpu->info->pfpfw, ret);
adreno_gpu->info->pfpfw, ret);
return ret;
}
ret = msm_gpu_init(drm, pdev, &gpu->base, &funcs->base,
gpu->info->name, "kgsl_3d0_reg_memory", "kgsl_3d0_irq",
ret = msm_gpu_init(drm, pdev, &adreno_gpu->base, &funcs->base,
adreno_gpu->info->name, "kgsl_3d0_reg_memory", "kgsl_3d0_irq",
RB_SIZE);
if (ret)
return ret;
mmu = gpu->base.mmu;
mmu = gpu->mmu;
if (mmu) {
ret = mmu->funcs->attach(mmu, iommu_ports,
ARRAY_SIZE(iommu_ports));
......@@ -371,24 +348,24 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
}
mutex_lock(&drm->struct_mutex);
gpu->memptrs_bo = msm_gem_new(drm, sizeof(*gpu->memptrs),
adreno_gpu->memptrs_bo = msm_gem_new(drm, sizeof(*adreno_gpu->memptrs),
MSM_BO_UNCACHED);
mutex_unlock(&drm->struct_mutex);
if (IS_ERR(gpu->memptrs_bo)) {
ret = PTR_ERR(gpu->memptrs_bo);
gpu->memptrs_bo = NULL;
if (IS_ERR(adreno_gpu->memptrs_bo)) {
ret = PTR_ERR(adreno_gpu->memptrs_bo);
adreno_gpu->memptrs_bo = NULL;
dev_err(drm->dev, "could not allocate memptrs: %d\n", ret);
return ret;
}
gpu->memptrs = msm_gem_vaddr(gpu->memptrs_bo);
if (!gpu->memptrs) {
adreno_gpu->memptrs = msm_gem_vaddr(adreno_gpu->memptrs_bo);
if (!adreno_gpu->memptrs) {
dev_err(drm->dev, "could not vmap memptrs\n");
return -ENOMEM;
}
ret = msm_gem_get_iova(gpu->memptrs_bo, gpu->base.id,
&gpu->memptrs_iova);
ret = msm_gem_get_iova(adreno_gpu->memptrs_bo, gpu->id,
&adreno_gpu->memptrs_iova);
if (ret) {
dev_err(drm->dev, "could not map memptrs: %d\n", ret);
return ret;
......
......@@ -39,7 +39,16 @@ struct adreno_gpu_funcs {
struct msm_gpu_funcs base;
};
struct adreno_info;
struct adreno_info {
struct adreno_rev rev;
uint32_t revn;
const char *name;
const char *pm4fw, *pfpfw;
uint32_t gmem;
struct msm_gpu *(*init)(struct drm_device *dev);
};
const struct adreno_info *adreno_info(struct adreno_rev rev);
struct adreno_rbmemptrs {
volatile uint32_t rptr;
......@@ -55,6 +64,9 @@ struct adreno_gpu {
uint32_t revn; /* numeric revision name */
const struct adreno_gpu_funcs *funcs;
/* interesting register offsets to dump: */
const unsigned int *registers;
/* firmware: */
const struct firmware *pm4, *pfp;
......@@ -131,8 +143,7 @@ void adreno_dump(struct msm_gpu *gpu);
void adreno_wait_ring(struct msm_gpu *gpu, uint32_t ndwords);
int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
struct adreno_gpu *gpu, const struct adreno_gpu_funcs *funcs,
struct adreno_rev rev);
struct adreno_gpu *gpu, const struct adreno_gpu_funcs *funcs);
void adreno_gpu_cleanup(struct adreno_gpu *gpu);
......
......@@ -12,9 +12,9 @@ The rules-ng-ng source files this header was generated from are:
- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml ( 32901 bytes, from 2014-06-02 15:21:30)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 9859 bytes, from 2014-06-02 15:21:30)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 14477 bytes, from 2014-05-16 11:51:57)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 58020 bytes, from 2014-06-25 12:57:16)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 26602 bytes, from 2014-06-25 12:57:16)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 14960 bytes, from 2014-07-27 17:22:13)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 58020 bytes, from 2014-08-01 12:22:48)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 41068 bytes, from 2014-08-01 12:22:48)
Copyright (C) 2013-2014 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)
......@@ -163,12 +163,16 @@ enum adreno_pm4_type3_packets {
CP_INDIRECT_BUFFER_PFE = 63,
CP_SET_BIN = 76,
CP_TEST_TWO_MEMS = 113,
CP_REG_WR_NO_CTXT = 120,
CP_RECORD_PFP_TIMESTAMP = 17,
CP_WAIT_FOR_ME = 19,
CP_SET_DRAW_STATE = 67,
CP_DRAW_INDX_OFFSET = 56,
CP_DRAW_INDIRECT = 40,
CP_DRAW_INDX_INDIRECT = 41,
CP_DRAW_AUTO = 36,
CP_UNKNOWN_1A = 26,
CP_WIDE_REG_WRITE = 116,
IN_IB_PREFETCH_END = 23,
IN_SUBBLK_PREFETCH = 31,
IN_INSTR_PREFETCH = 32,
......
......@@ -10,14 +10,14 @@ 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 ( 647 bytes, from 2013-11-30 14:45:35)
- /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 ( 17996 bytes, from 2013-12-01 19:10:31)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 1615 bytes, from 2013-11-30 15:00:52)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 22517 bytes, from 2014-06-25 12:55:02)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20457 bytes, from 2014-08-01 12:22:48)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 1615 bytes, from 2014-07-17 15:34:33)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 22517 bytes, from 2014-07-17 15:34:33)
- /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 ( 1544 bytes, from 2013-08-16 19:17:05)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2014-08-01 12:23:53)
- /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 ( 23613 bytes, from 2014-06-25 12:53:44)
- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 23613 bytes, from 2014-07-17 15:33:30)
Copyright (C) 2013 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)
......
......@@ -10,16 +10,16 @@ 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 ( 647 bytes, from 2013-11-30 14:45:35)
- /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 ( 17996 bytes, from 2013-12-01 19:10:31)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 1615 bytes, from 2013-11-30 15:00:52)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 22517 bytes, from 2014-06-25 12:55:02)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20457 bytes, from 2014-08-01 12:22:48)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 1615 bytes, from 2014-07-17 15:34:33)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 22517 bytes, from 2014-07-17 15:34:33)
- /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 ( 1544 bytes, from 2013-08-16 19:17:05)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2014-08-01 12:23:53)
- /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 ( 23613 bytes, from 2014-06-25 12:53:44)
- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 23613 bytes, from 2014-07-17 15:33:30)
Copyright (C) 2013 by the following authors:
Copyright (C) 2013-2014 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)
Permission is hereby granted, free of charge, to any person obtaining
......@@ -112,5 +112,11 @@ static inline uint32_t MMSS_CC_CLK_NS_VAL(uint32_t val)
return ((val) << MMSS_CC_CLK_NS_VAL__SHIFT) & MMSS_CC_CLK_NS_VAL__MASK;
}
#define REG_MMSS_CC_DSI2_PIXEL_CC 0x00000094
#define REG_MMSS_CC_DSI2_PIXEL_NS 0x000000e4
#define REG_MMSS_CC_DSI2_PIXEL_CC2 0x00000264
#endif /* MMSS_CC_XML */
......@@ -10,14 +10,14 @@ 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 ( 647 bytes, from 2013-11-30 14:45:35)
- /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 ( 17996 bytes, from 2013-12-01 19:10:31)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 1615 bytes, from 2013-11-30 15:00:52)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 22517 bytes, from 2014-06-25 12:55:02)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20457 bytes, from 2014-08-01 12:22:48)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 1615 bytes, from 2014-07-17 15:34:33)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 22517 bytes, from 2014-07-17 15:34:33)
- /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 ( 1544 bytes, from 2013-08-16 19:17:05)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2014-08-01 12:23:53)
- /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 ( 23613 bytes, from 2014-06-25 12:53:44)
- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 23613 bytes, from 2014-07-17 15:33:30)
Copyright (C) 2013 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)
......
......@@ -123,7 +123,7 @@ struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
for (i = 0; i < config->hpd_reg_cnt; i++) {
struct regulator *reg;
reg = devm_regulator_get_exclusive(&pdev->dev,
reg = devm_regulator_get(&pdev->dev,
config->hpd_reg_names[i]);
if (IS_ERR(reg)) {
ret = PTR_ERR(reg);
......@@ -139,7 +139,7 @@ struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
for (i = 0; i < config->pwr_reg_cnt; i++) {
struct regulator *reg;
reg = devm_regulator_get_exclusive(&pdev->dev,
reg = devm_regulator_get(&pdev->dev,
config->pwr_reg_names[i]);
if (IS_ERR(reg)) {
ret = PTR_ERR(reg);
......
......@@ -10,14 +10,14 @@ 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 ( 647 bytes, from 2013-11-30 14:45:35)
- /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 ( 17996 bytes, from 2013-12-01 19:10:31)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 1615 bytes, from 2013-11-30 15:00:52)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 22517 bytes, from 2014-06-25 12:55:02)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20457 bytes, from 2014-08-01 12:22:48)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 1615 bytes, from 2014-07-17 15:34:33)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 22517 bytes, from 2014-07-17 15:34:33)
- /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 ( 1544 bytes, from 2013-08-16 19:17:05)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2014-08-01 12:23:53)
- /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 ( 23613 bytes, from 2014-06-25 12:53:44)
- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 23613 bytes, from 2014-07-17 15:33:30)
Copyright (C) 2013-2014 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)
......
......@@ -10,14 +10,14 @@ 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 ( 647 bytes, from 2013-11-30 14:45:35)
- /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 ( 17996 bytes, from 2013-12-01 19:10:31)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 1615 bytes, from 2013-11-30 15:00:52)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 22517 bytes, from 2014-06-25 12:55:02)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20457 bytes, from 2014-08-01 12:22:48)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 1615 bytes, from 2014-07-17 15:34:33)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 22517 bytes, from 2014-07-17 15:34:33)
- /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 ( 1544 bytes, from 2013-08-16 19:17:05)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2014-08-01 12:23:53)
- /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 ( 23613 bytes, from 2014-06-25 12:53:44)
- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 23613 bytes, from 2014-07-17 15:33:30)
Copyright (C) 2013 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)
......
......@@ -10,16 +10,16 @@ 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 ( 647 bytes, from 2013-11-30 14:45:35)
- /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 ( 17996 bytes, from 2013-12-01 19:10:31)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 1615 bytes, from 2013-11-30 15:00:52)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 22517 bytes, from 2014-06-25 12:55:02)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20457 bytes, from 2014-08-01 12:22:48)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 1615 bytes, from 2014-07-17 15:34:33)
- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 22517 bytes, from 2014-07-17 15:34:33)
- /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 ( 1544 bytes, from 2013-08-16 19:17:05)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2014-08-01 12:23:53)
- /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 ( 23613 bytes, from 2014-06-25 12:53:44)
- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 23613 bytes, from 2014-07-17 15:33:30)
Copyright (C) 2013 by the following authors:
Copyright (C) 2013-2014 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)
Permission is hereby granted, free of charge, to any person obtaining
......@@ -871,6 +871,101 @@ static inline uint32_t MDP4_LCDC_UNDERFLOW_CLR_COLOR(uint32_t val)
#define MDP4_LCDC_CTRL_POLARITY_VSYNC_LOW 0x00000002
#define MDP4_LCDC_CTRL_POLARITY_DATA_EN_LOW 0x00000004
#define REG_MDP4_LCDC_LVDS_INTF_CTL 0x000c2000
#define MDP4_LCDC_LVDS_INTF_CTL_MODE_SEL 0x00000004
#define MDP4_LCDC_LVDS_INTF_CTL_RGB_OUT 0x00000008
#define MDP4_LCDC_LVDS_INTF_CTL_CH_SWAP 0x00000010
#define MDP4_LCDC_LVDS_INTF_CTL_CH1_RES_BIT 0x00000020
#define MDP4_LCDC_LVDS_INTF_CTL_CH2_RES_BIT 0x00000040
#define MDP4_LCDC_LVDS_INTF_CTL_ENABLE 0x00000080
#define MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE0_EN 0x00000100
#define MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE1_EN 0x00000200
#define MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE2_EN 0x00000400
#define MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE3_EN 0x00000800
#define MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE0_EN 0x00001000
#define MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE1_EN 0x00002000
#define MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE2_EN 0x00004000
#define MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE3_EN 0x00008000
#define MDP4_LCDC_LVDS_INTF_CTL_CH1_CLK_LANE_EN 0x00010000
#define MDP4_LCDC_LVDS_INTF_CTL_CH2_CLK_LANE_EN 0x00020000
static inline uint32_t REG_MDP4_LCDC_LVDS_MUX_CTL(uint32_t i0) { return 0x000c2014 + 0x8*i0; }
static inline uint32_t REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(uint32_t i0) { return 0x000c2014 + 0x8*i0; }
#define MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0__MASK 0x000000ff
#define MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0__SHIFT 0
static inline uint32_t MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(uint32_t val)
{
return ((val) << MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0__SHIFT) & MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0__MASK;
}
#define MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1__MASK 0x0000ff00
#define MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1__SHIFT 8
static inline uint32_t MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(uint32_t val)
{
return ((val) << MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1__SHIFT) & MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1__MASK;
}
#define MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2__MASK 0x00ff0000
#define MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2__SHIFT 16
static inline uint32_t MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(uint32_t val)
{
return ((val) << MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2__SHIFT) & MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2__MASK;
}
#define MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3__MASK 0xff000000
#define MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3__SHIFT 24
static inline uint32_t MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(uint32_t val)
{
return ((val) << MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3__SHIFT) & MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3__MASK;
}
static inline uint32_t REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(uint32_t i0) { return 0x000c2018 + 0x8*i0; }
#define MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4__MASK 0x000000ff
#define MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4__SHIFT 0
static inline uint32_t MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(uint32_t val)
{
return ((val) << MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4__SHIFT) & MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4__MASK;
}
#define MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5__MASK 0x0000ff00
#define MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5__SHIFT 8
static inline uint32_t MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(uint32_t val)
{
return ((val) << MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5__SHIFT) & MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5__MASK;
}
#define MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6__MASK 0x00ff0000
#define MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6__SHIFT 16
static inline uint32_t MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(uint32_t val)
{
return ((val) << MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6__SHIFT) & MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6__MASK;
}
#define REG_MDP4_LCDC_LVDS_PHY_RESET 0x000c2034
#define REG_MDP4_LVDS_PHY_PLL_CTRL_0 0x000c3000
#define REG_MDP4_LVDS_PHY_PLL_CTRL_1 0x000c3004
#define REG_MDP4_LVDS_PHY_PLL_CTRL_2 0x000c3008
#define REG_MDP4_LVDS_PHY_PLL_CTRL_3 0x000c300c
#define REG_MDP4_LVDS_PHY_PLL_CTRL_5 0x000c3014
#define REG_MDP4_LVDS_PHY_PLL_CTRL_6 0x000c3018
#define REG_MDP4_LVDS_PHY_PLL_CTRL_7 0x000c301c
#define REG_MDP4_LVDS_PHY_PLL_CTRL_8 0x000c3020
#define REG_MDP4_LVDS_PHY_PLL_CTRL_9 0x000c3024
#define REG_MDP4_LVDS_PHY_PLL_LOCKED 0x000c3080
#define REG_MDP4_LVDS_PHY_CFG2 0x000c3108
#define REG_MDP4_LVDS_PHY_CFG0 0x000c3100
#define MDP4_LVDS_PHY_CFG0_SERIALIZATION_ENBLE 0x00000010
#define MDP4_LVDS_PHY_CFG0_CHANNEL0 0x00000040
#define MDP4_LVDS_PHY_CFG0_CHANNEL1 0x00000080
#define REG_MDP4_DTV 0x000d0000
#define REG_MDP4_DTV_ENABLE 0x000d0000
......
......@@ -273,14 +273,17 @@ static void blend_setup(struct drm_crtc *crtc)
};
bool alpha[4]= { false, false, false, false };
/* Don't rely on value read back from hw, but instead use our
* own shadowed value. Possibly disable/reenable looses the
* previous value and goes back to power-on default?
*/
mixer_cfg = mdp4_kms->mixer_cfg;
mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_LOW0(ovlp), 0);
mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_LOW1(ovlp), 0);
mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_HIGH0(ovlp), 0);
mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_HIGH1(ovlp), 0);
/* TODO single register for all CRTCs, so this won't work properly
* when multiple CRTCs are active..
*/
for (i = 0; i < ARRAY_SIZE(mdp4_crtc->planes); i++) {
struct drm_plane *plane = mdp4_crtc->planes[i];
if (plane) {
......@@ -291,7 +294,8 @@ static void blend_setup(struct drm_crtc *crtc)
to_mdp_format(msm_framebuffer_format(plane->fb));
alpha[idx-1] = format->alpha_enable;
}
mixer_cfg |= mixercfg(mdp4_crtc->mixer, pipe_id, stages[idx]);
mixer_cfg = mixercfg(mixer_cfg, mdp4_crtc->mixer,
pipe_id, stages[idx]);
}
}
......@@ -320,6 +324,7 @@ static void blend_setup(struct drm_crtc *crtc)
mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_TRANSP_HIGH1(ovlp, i), 0);
}
mdp4_kms->mixer_cfg = mixer_cfg;
mdp4_write(mdp4_kms, REG_MDP4_LAYERMIXER_IN_CFG, mixer_cfg);
}
......@@ -670,7 +675,7 @@ void mdp4_crtc_set_config(struct drm_crtc *crtc, uint32_t config)
}
/* set interface for routing crtc->encoder: */
void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf)
void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf, int mixer)
{
struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
struct mdp4_kms *mdp4_kms = get_kms(crtc);
......@@ -696,15 +701,13 @@ void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf)
if (intf == INTF_DSI_VIDEO) {
intf_sel &= ~MDP4_DISP_INTF_SEL_DSI_CMD;
intf_sel |= MDP4_DISP_INTF_SEL_DSI_VIDEO;
mdp4_crtc->mixer = 0;
} else if (intf == INTF_DSI_CMD) {
intf_sel &= ~MDP4_DISP_INTF_SEL_DSI_VIDEO;
intf_sel |= MDP4_DISP_INTF_SEL_DSI_CMD;
mdp4_crtc->mixer = 0;
} else if (intf == INTF_LCDC_DTV){
mdp4_crtc->mixer = 1;
}
mdp4_crtc->mixer = mixer;
blend_setup(crtc);
DBG("%s: intf_sel=%08x", mdp4_crtc->name, intf_sel);
......
......@@ -233,7 +233,7 @@ static void mdp4_dtv_encoder_commit(struct drm_encoder *encoder)
MDP4_DMA_CONFIG_G_BPC(BPC8) |
MDP4_DMA_CONFIG_B_BPC(BPC8) |
MDP4_DMA_CONFIG_PACK(0x21));
mdp4_crtc_set_intf(encoder->crtc, INTF_LCDC_DTV);
mdp4_crtc_set_intf(encoder->crtc, INTF_LCDC_DTV, 1);
mdp4_dtv_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
}
......
......@@ -106,6 +106,7 @@ static int mdp4_hw_init(struct msm_kms *kms)
if (mdp4_kms->rev >= 2)
mdp4_write(mdp4_kms, REG_MDP4_LAYERMIXER_IN_CFG_UPDATE_METHOD, 1);
mdp4_write(mdp4_kms, REG_MDP4_LAYERMIXER_IN_CFG, 0);
/* disable CSC matrix / YUV by default: */
mdp4_write(mdp4_kms, REG_MDP4_PIPE_OP_MODE(VG1), 0);
......@@ -196,6 +197,28 @@ int mdp4_enable(struct mdp4_kms *mdp4_kms)
return 0;
}
#ifdef CONFIG_OF
static struct drm_panel *detect_panel(struct drm_device *dev, const char *name)
{
struct device_node *n;
struct drm_panel *panel = NULL;
n = of_parse_phandle(dev->dev->of_node, name, 0);
if (n) {
panel = of_drm_find_panel(n);
if (!panel)
panel = ERR_PTR(-EPROBE_DEFER);
}
return panel;
}
#else
static struct drm_panel *detect_panel(struct drm_device *dev, const char *name)
{
// ??? maybe use a module param to specify which panel is attached?
}
#endif
static int modeset_init(struct mdp4_kms *mdp4_kms)
{
struct drm_device *dev = mdp4_kms->dev;
......@@ -203,14 +226,11 @@ static int modeset_init(struct mdp4_kms *mdp4_kms)
struct drm_plane *plane;
struct drm_crtc *crtc;
struct drm_encoder *encoder;
struct drm_connector *connector;
struct drm_panel *panel;
struct hdmi *hdmi;
int ret;
/*
* NOTE: this is a bit simplistic until we add support
* for more than just RGB1->DMA_E->DTV->HDMI
*/
/* construct non-private planes: */
plane = mdp4_plane_init(dev, VG1, false);
if (IS_ERR(plane)) {
......@@ -228,7 +248,57 @@ static int modeset_init(struct mdp4_kms *mdp4_kms)
}
priv->planes[priv->num_planes++] = plane;
/* the CRTCs get constructed with a private plane: */
/*
* Setup the LCDC/LVDS path: RGB2 -> DMA_P -> LCDC -> LVDS:
*/
panel = detect_panel(dev, "qcom,lvds-panel");
if (IS_ERR(panel)) {
ret = PTR_ERR(panel);
dev_err(dev->dev, "failed to detect LVDS panel: %d\n", ret);
goto fail;
}
plane = mdp4_plane_init(dev, RGB2, true);
if (IS_ERR(plane)) {
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);
if (IS_ERR(crtc)) {
dev_err(dev->dev, "failed to construct crtc for DMA_P\n");
ret = PTR_ERR(crtc);
goto fail;
}
encoder = mdp4_lcdc_encoder_init(dev, panel);
if (IS_ERR(encoder)) {
dev_err(dev->dev, "failed to construct LCDC encoder\n");
ret = PTR_ERR(encoder);
goto fail;
}
/* LCDC can be hooked to DMA_P: */
encoder->possible_crtcs = 1 << priv->num_crtcs;
priv->crtcs[priv->num_crtcs++] = crtc;
priv->encoders[priv->num_encoders++] = encoder;
connector = mdp4_lvds_connector_init(dev, panel, encoder);
if (IS_ERR(connector)) {
ret = PTR_ERR(connector);
dev_err(dev->dev, "failed to initialize LVDS connector: %d\n", ret);
goto fail;
}
priv->connectors[priv->num_connectors++] = connector;
/*
* Setup DTV/HDMI path: RGB1 -> DMA_E -> DTV -> HDMI:
*/
plane = mdp4_plane_init(dev, RGB1, true);
if (IS_ERR(plane)) {
dev_err(dev->dev, "failed to construct plane for RGB1\n");
......@@ -242,7 +312,6 @@ static int modeset_init(struct mdp4_kms *mdp4_kms)
ret = PTR_ERR(crtc);
goto fail;
}
priv->crtcs[priv->num_crtcs++] = crtc;
encoder = mdp4_dtv_encoder_init(dev);
if (IS_ERR(encoder)) {
......@@ -250,7 +319,11 @@ static int modeset_init(struct mdp4_kms *mdp4_kms)
ret = PTR_ERR(encoder);
goto fail;
}
encoder->possible_crtcs = 0x1; /* DTV can be hooked to DMA_E */
/* DTV can be hooked to DMA_E: */
encoder->possible_crtcs = 1 << priv->num_crtcs;
priv->crtcs[priv->num_crtcs++] = crtc;
priv->encoders[priv->num_encoders++] = encoder;
hdmi = hdmi_init(dev, encoder);
......
......@@ -23,6 +23,8 @@
#include "mdp/mdp_kms.h"
#include "mdp4.xml.h"
#include "drm_panel.h"
struct mdp4_kms {
struct mdp_kms base;
......@@ -30,6 +32,13 @@ struct mdp4_kms {
int rev;
/* Shadow value for MDP4_LAYERMIXER_IN_CFG.. since setup for all
* crtcs/encoders is in one shared register, we need to update it
* via read/modify/write. But to avoid getting confused by power-
* on-default values after resume, use this shadow value instead:
*/
uint32_t mixer_cfg;
/* mapper-id used to request GEM buffer mapped for scanout: */
int id;
......@@ -74,7 +83,7 @@ static inline uint32_t pipe2flush(enum mdp4_pipe pipe)
case VG1: return MDP4_OVERLAY_FLUSH_VG1;
case VG2: return MDP4_OVERLAY_FLUSH_VG2;
case RGB1: return MDP4_OVERLAY_FLUSH_RGB1;
case RGB2: return MDP4_OVERLAY_FLUSH_RGB1;
case RGB2: return MDP4_OVERLAY_FLUSH_RGB2;
default: return 0;
}
}
......@@ -108,38 +117,50 @@ static inline uint32_t dma2err(enum mdp4_dma dma)
}
}
static inline uint32_t mixercfg(int mixer, enum mdp4_pipe pipe,
enum mdp_mixer_stage_id stage)
static inline uint32_t mixercfg(uint32_t mixer_cfg, int mixer,
enum mdp4_pipe pipe, enum mdp_mixer_stage_id stage)
{
uint32_t mixer_cfg = 0;
switch (pipe) {
case VG1:
mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE0(stage) |
mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE0__MASK |
MDP4_LAYERMIXER_IN_CFG_PIPE0_MIXER1);
mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE0(stage) |
COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE0_MIXER1);
break;
case VG2:
mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE1(stage) |
mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE1__MASK |
MDP4_LAYERMIXER_IN_CFG_PIPE1_MIXER1);
mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE1(stage) |
COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE1_MIXER1);
break;
case RGB1:
mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE2(stage) |
mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE2__MASK |
MDP4_LAYERMIXER_IN_CFG_PIPE2_MIXER1);
mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE2(stage) |
COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE2_MIXER1);
break;
case RGB2:
mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE3(stage) |
mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE3__MASK |
MDP4_LAYERMIXER_IN_CFG_PIPE3_MIXER1);
mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE3(stage) |
COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE3_MIXER1);
break;
case RGB3:
mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE4(stage) |
mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE4__MASK |
MDP4_LAYERMIXER_IN_CFG_PIPE4_MIXER1);
mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE4(stage) |
COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE4_MIXER1);
break;
case VG3:
mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE5(stage) |
mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE5__MASK |
MDP4_LAYERMIXER_IN_CFG_PIPE5_MIXER1);
mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE5(stage) |
COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE5_MIXER1);
break;
case VG4:
mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE6(stage) |
mixer_cfg &= ~(MDP4_LAYERMIXER_IN_CFG_PIPE6__MASK |
MDP4_LAYERMIXER_IN_CFG_PIPE6_MIXER1);
mixer_cfg |= MDP4_LAYERMIXER_IN_CFG_PIPE6(stage) |
COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE6_MIXER1);
break;
default:
......@@ -188,7 +209,7 @@ struct drm_plane *mdp4_plane_init(struct drm_device *dev,
uint32_t mdp4_crtc_vblank(struct drm_crtc *crtc);
void mdp4_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file);
void mdp4_crtc_set_config(struct drm_crtc *crtc, uint32_t config);
void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf);
void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf, int mixer);
void mdp4_crtc_attach(struct drm_crtc *crtc, struct drm_plane *plane);
void mdp4_crtc_detach(struct drm_crtc *crtc, struct drm_plane *plane);
struct drm_crtc *mdp4_crtc_init(struct drm_device *dev,
......@@ -198,6 +219,22 @@ struct drm_crtc *mdp4_crtc_init(struct drm_device *dev,
long mdp4_dtv_round_pixclk(struct drm_encoder *encoder, unsigned long rate);
struct drm_encoder *mdp4_dtv_encoder_init(struct drm_device *dev);
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_panel *panel);
struct drm_connector *mdp4_lvds_connector_init(struct drm_device *dev,
struct drm_panel *panel, struct drm_encoder *encoder);
#ifdef CONFIG_COMMON_CLK
struct clk *mpd4_lvds_pll_init(struct drm_device *dev);
#else
static inline struct clk *mpd4_lvds_pll_init(struct drm_device *dev)
{
return ERR_PTR(-ENODEV);
}
#endif
#ifdef CONFIG_MSM_BUS_SCALING
static inline int match_dev_name(struct device *dev, void *data)
{
......
/*
* Copyright (C) 2014 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
* 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_lcdc_encoder {
struct drm_encoder base;
struct drm_panel *panel;
struct clk *lcdc_clk;
unsigned long int pixclock;
struct regulator *regs[3];
bool enabled;
uint32_t bsc;
};
#define to_mdp4_lcdc_encoder(x) container_of(x, struct mdp4_lcdc_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));
}
#ifdef CONFIG_MSM_BUS_SCALING
#include <mach/board.h>
static void bs_init(struct mdp4_lcdc_encoder *mdp4_lcdc_encoder)
{
struct drm_device *dev = mdp4_lcdc_encoder->base.dev;
struct lcdc_platform_data *lcdc_pdata = mdp4_find_pdata("lvds.0");
if (!lcdc_pdata) {
dev_err(dev->dev, "could not find lvds pdata\n");
return;
}
if (lcdc_pdata->bus_scale_table) {
mdp4_lcdc_encoder->bsc = msm_bus_scale_register_client(
lcdc_pdata->bus_scale_table);
DBG("lvds : bus scale client: %08x", mdp4_lcdc_encoder->bsc);
}
}
static void bs_fini(struct mdp4_lcdc_encoder *mdp4_lcdc_encoder)
{
if (mdp4_lcdc_encoder->bsc) {
msm_bus_scale_unregister_client(mdp4_lcdc_encoder->bsc);
mdp4_lcdc_encoder->bsc = 0;
}
}
static void bs_set(struct mdp4_lcdc_encoder *mdp4_lcdc_encoder, int idx)
{
if (mdp4_lcdc_encoder->bsc) {
DBG("set bus scaling: %d", idx);
msm_bus_scale_client_update_request(mdp4_lcdc_encoder->bsc, idx);
}
}
#else
static void bs_init(struct mdp4_lcdc_encoder *mdp4_lcdc_encoder) {}
static void bs_fini(struct mdp4_lcdc_encoder *mdp4_lcdc_encoder) {}
static void bs_set(struct mdp4_lcdc_encoder *mdp4_lcdc_encoder, int idx) {}
#endif
static void mdp4_lcdc_encoder_destroy(struct drm_encoder *encoder)
{
struct mdp4_lcdc_encoder *mdp4_lcdc_encoder =
to_mdp4_lcdc_encoder(encoder);
bs_fini(mdp4_lcdc_encoder);
drm_encoder_cleanup(encoder);
kfree(mdp4_lcdc_encoder);
}
static const struct drm_encoder_funcs mdp4_lcdc_encoder_funcs = {
.destroy = mdp4_lcdc_encoder_destroy,
};
/* this should probably be a helper: */
struct drm_connector *get_connector(struct drm_encoder *encoder)
{
struct drm_device *dev = encoder->dev;
struct drm_connector *connector;
list_for_each_entry(connector, &dev->mode_config.connector_list, head)
if (connector->encoder == encoder)
return connector;
return NULL;
}
static void setup_phy(struct drm_encoder *encoder)
{
struct drm_device *dev = encoder->dev;
struct drm_connector *connector = get_connector(encoder);
struct mdp4_kms *mdp4_kms = get_kms(encoder);
uint32_t lvds_intf = 0, lvds_phy_cfg0 = 0;
int bpp, nchan, swap;
if (!connector)
return;
bpp = 3 * connector->display_info.bpc;
if (!bpp)
bpp = 18;
/* TODO, these should come from panel somehow: */
nchan = 1;
swap = 0;
switch (bpp) {
case 24:
mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(0),
MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x08) |
MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x05) |
MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x04) |
MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x03));
mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(0),
MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x02) |
MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x01) |
MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x00));
mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(1),
MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x11) |
MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x10) |
MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x0d) |
MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x0c));
mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(1),
MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x0b) |
MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x0a) |
MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x09));
mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(2),
MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x1a) |
MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x19) |
MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x18) |
MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x15));
mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(2),
MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x14) |
MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x13) |
MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x12));
mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(3),
MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x1b) |
MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x17) |
MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x16) |
MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x0f));
mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(3),
MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x0e) |
MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x07) |
MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x06));
if (nchan == 2) {
lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE3_EN |
MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE2_EN |
MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE1_EN |
MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE0_EN |
MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE3_EN |
MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE2_EN |
MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE1_EN |
MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE0_EN;
} else {
lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE3_EN |
MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE2_EN |
MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE1_EN |
MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE0_EN;
}
break;
case 18:
mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(0),
MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x0a) |
MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x07) |
MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x06) |
MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x05));
mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(0),
MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x04) |
MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x03) |
MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x02));
mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(1),
MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x13) |
MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x12) |
MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x0f) |
MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x0e));
mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(1),
MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x0d) |
MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x0c) |
MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x0b));
mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_3_TO_0(2),
MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT0(0x1a) |
MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT1(0x19) |
MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT2(0x18) |
MDP4_LCDC_LVDS_MUX_CTL_3_TO_0_BIT3(0x17));
mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_MUX_CTL_6_TO_4(2),
MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT4(0x16) |
MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT5(0x15) |
MDP4_LCDC_LVDS_MUX_CTL_6_TO_4_BIT6(0x14));
if (nchan == 2) {
lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE2_EN |
MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE1_EN |
MDP4_LCDC_LVDS_INTF_CTL_CH2_DATA_LANE0_EN |
MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE2_EN |
MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE1_EN |
MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE0_EN;
} else {
lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE2_EN |
MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE1_EN |
MDP4_LCDC_LVDS_INTF_CTL_CH1_DATA_LANE0_EN;
}
lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_RGB_OUT;
break;
default:
dev_err(dev->dev, "unknown bpp: %d\n", bpp);
return;
}
switch (nchan) {
case 1:
lvds_phy_cfg0 = MDP4_LVDS_PHY_CFG0_CHANNEL0;
lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_CH1_CLK_LANE_EN |
MDP4_LCDC_LVDS_INTF_CTL_MODE_SEL;
break;
case 2:
lvds_phy_cfg0 = MDP4_LVDS_PHY_CFG0_CHANNEL0 |
MDP4_LVDS_PHY_CFG0_CHANNEL1;
lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_CH2_CLK_LANE_EN |
MDP4_LCDC_LVDS_INTF_CTL_CH1_CLK_LANE_EN;
break;
default:
dev_err(dev->dev, "unknown # of channels: %d\n", nchan);
return;
}
if (swap)
lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_CH_SWAP;
lvds_intf |= MDP4_LCDC_LVDS_INTF_CTL_ENABLE;
mdp4_write(mdp4_kms, REG_MDP4_LVDS_PHY_CFG0, lvds_phy_cfg0);
mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_INTF_CTL, lvds_intf);
mdp4_write(mdp4_kms, REG_MDP4_LVDS_PHY_CFG2, 0x30);
mb();
udelay(1);
lvds_phy_cfg0 |= MDP4_LVDS_PHY_CFG0_SERIALIZATION_ENBLE;
mdp4_write(mdp4_kms, REG_MDP4_LVDS_PHY_CFG0, lvds_phy_cfg0);
}
static void mdp4_lcdc_encoder_dpms(struct drm_encoder *encoder, int mode)
{
struct drm_device *dev = encoder->dev;
struct mdp4_lcdc_encoder *mdp4_lcdc_encoder =
to_mdp4_lcdc_encoder(encoder);
struct mdp4_kms *mdp4_kms = get_kms(encoder);
struct drm_panel *panel = mdp4_lcdc_encoder->panel;
bool enabled = (mode == DRM_MODE_DPMS_ON);
int i, ret;
DBG("mode=%d", mode);
if (enabled == mdp4_lcdc_encoder->enabled)
return;
if (enabled) {
unsigned long pc = mdp4_lcdc_encoder->pixclock;
int ret;
bs_set(mdp4_lcdc_encoder, 1);
for (i = 0; i < ARRAY_SIZE(mdp4_lcdc_encoder->regs); i++) {
ret = regulator_enable(mdp4_lcdc_encoder->regs[i]);
if (ret)
dev_err(dev->dev, "failed to enable regulator: %d\n", ret);
}
DBG("setting lcdc_clk=%lu", pc);
ret = clk_set_rate(mdp4_lcdc_encoder->lcdc_clk, pc);
if (ret)
dev_err(dev->dev, "failed to configure lcdc_clk: %d\n", ret);
ret = clk_prepare_enable(mdp4_lcdc_encoder->lcdc_clk);
if (ret)
dev_err(dev->dev, "failed to enable lcdc_clk: %d\n", ret);
if (panel)
drm_panel_enable(panel);
setup_phy(encoder);
mdp4_write(mdp4_kms, REG_MDP4_LCDC_ENABLE, 1);
} else {
mdp4_write(mdp4_kms, REG_MDP4_LCDC_ENABLE, 0);
if (panel)
drm_panel_disable(panel);
/*
* 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);
clk_disable_unprepare(mdp4_lcdc_encoder->lcdc_clk);
for (i = 0; i < ARRAY_SIZE(mdp4_lcdc_encoder->regs); i++) {
ret = regulator_disable(mdp4_lcdc_encoder->regs[i]);
if (ret)
dev_err(dev->dev, "failed to disable regulator: %d\n", ret);
}
bs_set(mdp4_lcdc_encoder, 0);
}
mdp4_lcdc_encoder->enabled = enabled;
}
static bool mdp4_lcdc_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
return true;
}
static void mdp4_lcdc_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
struct mdp4_lcdc_encoder *mdp4_lcdc_encoder =
to_mdp4_lcdc_encoder(encoder);
struct mdp4_kms *mdp4_kms = get_kms(encoder);
uint32_t lcdc_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);
mdp4_lcdc_encoder->pixclock = mode->clock * 1000;
DBG("pixclock=%lu", mdp4_lcdc_encoder->pixclock);
ctrl_pol = 0;
if (mode->flags & DRM_MODE_FLAG_NHSYNC)
ctrl_pol |= MDP4_LCDC_CTRL_POLARITY_HSYNC_LOW;
if (mode->flags & DRM_MODE_FLAG_NVSYNC)
ctrl_pol |= MDP4_LCDC_CTRL_POLARITY_VSYNC_LOW;
/* probably need to get DATA_EN polarity from panel.. */
lcdc_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 + lcdc_hsync_skew;
display_v_end = vsync_period - ((mode->vsync_start - mode->vdisplay) * mode->htotal) + lcdc_hsync_skew - 1;
mdp4_write(mdp4_kms, REG_MDP4_LCDC_HSYNC_CTRL,
MDP4_LCDC_HSYNC_CTRL_PULSEW(mode->hsync_end - mode->hsync_start) |
MDP4_LCDC_HSYNC_CTRL_PERIOD(mode->htotal));
mdp4_write(mdp4_kms, REG_MDP4_LCDC_VSYNC_PERIOD, vsync_period);
mdp4_write(mdp4_kms, REG_MDP4_LCDC_VSYNC_LEN, vsync_len);
mdp4_write(mdp4_kms, REG_MDP4_LCDC_DISPLAY_HCTRL,
MDP4_LCDC_DISPLAY_HCTRL_START(hsync_start_x) |
MDP4_LCDC_DISPLAY_HCTRL_END(hsync_end_x));
mdp4_write(mdp4_kms, REG_MDP4_LCDC_DISPLAY_VSTART, display_v_start);
mdp4_write(mdp4_kms, REG_MDP4_LCDC_DISPLAY_VEND, display_v_end);
mdp4_write(mdp4_kms, REG_MDP4_LCDC_BORDER_CLR, 0);
mdp4_write(mdp4_kms, REG_MDP4_LCDC_UNDERFLOW_CLR,
MDP4_LCDC_UNDERFLOW_CLR_ENABLE_RECOVERY |
MDP4_LCDC_UNDERFLOW_CLR_COLOR(0xff));
mdp4_write(mdp4_kms, REG_MDP4_LCDC_HSYNC_SKEW, lcdc_hsync_skew);
mdp4_write(mdp4_kms, REG_MDP4_LCDC_CTRL_POLARITY, ctrl_pol);
mdp4_write(mdp4_kms, REG_MDP4_LCDC_ACTIVE_HCTL,
MDP4_LCDC_ACTIVE_HCTL_START(0) |
MDP4_LCDC_ACTIVE_HCTL_END(0));
mdp4_write(mdp4_kms, REG_MDP4_LCDC_ACTIVE_VSTART, 0);
mdp4_write(mdp4_kms, REG_MDP4_LCDC_ACTIVE_VEND, 0);
}
static void mdp4_lcdc_encoder_prepare(struct drm_encoder *encoder)
{
mdp4_lcdc_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
}
static void mdp4_lcdc_encoder_commit(struct drm_encoder *encoder)
{
/* TODO: hard-coded for 18bpp: */
mdp4_crtc_set_config(encoder->crtc,
MDP4_DMA_CONFIG_R_BPC(BPC6) |
MDP4_DMA_CONFIG_G_BPC(BPC6) |
MDP4_DMA_CONFIG_B_BPC(BPC6) |
MDP4_DMA_CONFIG_PACK_ALIGN_MSB |
MDP4_DMA_CONFIG_PACK(0x21) |
MDP4_DMA_CONFIG_DEFLKR_EN |
MDP4_DMA_CONFIG_DITHER_EN);
mdp4_crtc_set_intf(encoder->crtc, INTF_LCDC_DTV, 0);
mdp4_lcdc_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
}
static const struct drm_encoder_helper_funcs mdp4_lcdc_encoder_helper_funcs = {
.dpms = mdp4_lcdc_encoder_dpms,
.mode_fixup = mdp4_lcdc_encoder_mode_fixup,
.mode_set = mdp4_lcdc_encoder_mode_set,
.prepare = mdp4_lcdc_encoder_prepare,
.commit = mdp4_lcdc_encoder_commit,
};
long mdp4_lcdc_round_pixclk(struct drm_encoder *encoder, unsigned long rate)
{
struct mdp4_lcdc_encoder *mdp4_lcdc_encoder =
to_mdp4_lcdc_encoder(encoder);
return clk_round_rate(mdp4_lcdc_encoder->lcdc_clk, rate);
}
/* initialize encoder */
struct drm_encoder *mdp4_lcdc_encoder_init(struct drm_device *dev,
struct drm_panel *panel)
{
struct drm_encoder *encoder = NULL;
struct mdp4_lcdc_encoder *mdp4_lcdc_encoder;
struct regulator *reg;
int ret;
mdp4_lcdc_encoder = kzalloc(sizeof(*mdp4_lcdc_encoder), GFP_KERNEL);
if (!mdp4_lcdc_encoder) {
ret = -ENOMEM;
goto fail;
}
mdp4_lcdc_encoder->panel = panel;
encoder = &mdp4_lcdc_encoder->base;
drm_encoder_init(dev, encoder, &mdp4_lcdc_encoder_funcs,
DRM_MODE_ENCODER_LVDS);
drm_encoder_helper_add(encoder, &mdp4_lcdc_encoder_helper_funcs);
/* TODO: do we need different pll in other cases? */
mdp4_lcdc_encoder->lcdc_clk = mpd4_lvds_pll_init(dev);
if (IS_ERR(mdp4_lcdc_encoder->lcdc_clk)) {
dev_err(dev->dev, "failed to get lvds_clk\n");
ret = PTR_ERR(mdp4_lcdc_encoder->lcdc_clk);
goto fail;
}
/* TODO: different regulators in other cases? */
reg = devm_regulator_get(dev->dev, "lvds-vccs-3p3v");
if (IS_ERR(reg)) {
ret = PTR_ERR(reg);
dev_err(dev->dev, "failed to get lvds-vccs-3p3v: %d\n", ret);
goto fail;
}
mdp4_lcdc_encoder->regs[0] = reg;
reg = devm_regulator_get(dev->dev, "lvds-pll-vdda");
if (IS_ERR(reg)) {
ret = PTR_ERR(reg);
dev_err(dev->dev, "failed to get lvds-pll-vdda: %d\n", ret);
goto fail;
}
mdp4_lcdc_encoder->regs[1] = reg;
reg = devm_regulator_get(dev->dev, "lvds-vdda");
if (IS_ERR(reg)) {
ret = PTR_ERR(reg);
dev_err(dev->dev, "failed to get lvds-vdda: %d\n", ret);
goto fail;
}
mdp4_lcdc_encoder->regs[2] = reg;
bs_init(mdp4_lcdc_encoder);
return encoder;
fail:
if (encoder)
mdp4_lcdc_encoder_destroy(encoder);
return ERR_PTR(ret);
}
/*
* Copyright (C) 2014 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
* 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 <linux/gpio.h>
#include "mdp4_kms.h"
struct mdp4_lvds_connector {
struct drm_connector base;
struct drm_encoder *encoder;
struct drm_panel *panel;
};
#define to_mdp4_lvds_connector(x) container_of(x, struct mdp4_lvds_connector, base)
static enum drm_connector_status mdp4_lvds_connector_detect(
struct drm_connector *connector, bool force)
{
struct mdp4_lvds_connector *mdp4_lvds_connector =
to_mdp4_lvds_connector(connector);
return mdp4_lvds_connector->panel ?
connector_status_connected :
connector_status_disconnected;
}
static void mdp4_lvds_connector_destroy(struct drm_connector *connector)
{
struct mdp4_lvds_connector *mdp4_lvds_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_cleanup(connector);
kfree(mdp4_lvds_connector);
}
static int mdp4_lvds_connector_get_modes(struct drm_connector *connector)
{
struct mdp4_lvds_connector *mdp4_lvds_connector =
to_mdp4_lvds_connector(connector);
struct drm_panel *panel = mdp4_lvds_connector->panel;
int ret = 0;
if (panel)
ret = panel->funcs->get_modes(panel);
return ret;
}
static int mdp4_lvds_connector_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
struct mdp4_lvds_connector *mdp4_lvds_connector =
to_mdp4_lvds_connector(connector);
struct drm_encoder *encoder = mdp4_lvds_connector->encoder;
long actual, requested;
requested = 1000 * mode->clock;
actual = mdp4_lcdc_round_pixclk(encoder, requested);
DBG("requested=%ld, actual=%ld", requested, actual);
if (actual != requested)
return MODE_CLOCK_RANGE;
return MODE_OK;
}
static struct drm_encoder *
mdp4_lvds_connector_best_encoder(struct drm_connector *connector)
{
struct mdp4_lvds_connector *mdp4_lvds_connector =
to_mdp4_lvds_connector(connector);
return mdp4_lvds_connector->encoder;
}
static const struct drm_connector_funcs mdp4_lvds_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.detect = mdp4_lvds_connector_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = mdp4_lvds_connector_destroy,
};
static const struct drm_connector_helper_funcs mdp4_lvds_connector_helper_funcs = {
.get_modes = mdp4_lvds_connector_get_modes,
.mode_valid = mdp4_lvds_connector_mode_valid,
.best_encoder = mdp4_lvds_connector_best_encoder,
};
/* initialize connector */
struct drm_connector *mdp4_lvds_connector_init(struct drm_device *dev,
struct drm_panel *panel, struct drm_encoder *encoder)
{
struct drm_connector *connector = NULL;
struct mdp4_lvds_connector *mdp4_lvds_connector;
int ret;
mdp4_lvds_connector = kzalloc(sizeof(*mdp4_lvds_connector), GFP_KERNEL);
if (!mdp4_lvds_connector) {
ret = -ENOMEM;
goto fail;
}
mdp4_lvds_connector->encoder = encoder;
mdp4_lvds_connector->panel = panel;
connector = &mdp4_lvds_connector->base;
drm_connector_init(dev, connector, &mdp4_lvds_connector_funcs,
DRM_MODE_CONNECTOR_LVDS);
drm_connector_helper_add(connector, &mdp4_lvds_connector_helper_funcs);
connector->polled = 0;
connector->interlace_allowed = 0;
connector->doublescan_allowed = 0;
drm_connector_register(connector);
drm_mode_connector_attach_encoder(connector, encoder);
if (panel)
drm_panel_attach(panel, connector);
return connector;
fail:
if (connector)
mdp4_lvds_connector_destroy(connector);
return ERR_PTR(ret);
}
/*
* Copyright (C) 2014 Red Hat
* Author: Rob Clark <robdclark@gmail.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 <linux/clk.h>
#include <linux/clk-provider.h>
#include "mdp4_kms.h"
struct mdp4_lvds_pll {
struct clk_hw pll_hw;
struct drm_device *dev;
unsigned long pixclk;
};
#define to_mdp4_lvds_pll(x) container_of(x, struct mdp4_lvds_pll, pll_hw)
static struct mdp4_kms *get_kms(struct mdp4_lvds_pll *lvds_pll)
{
struct msm_drm_private *priv = lvds_pll->dev->dev_private;
return to_mdp4_kms(to_mdp_kms(priv->kms));
}
struct pll_rate {
unsigned long rate;
struct {
uint32_t val;
uint32_t reg;
} conf[32];
};
/* NOTE: keep sorted highest freq to lowest: */
static const struct pll_rate freqtbl[] = {
{ 72000000, {
{ 0x8f, REG_MDP4_LVDS_PHY_PLL_CTRL_1 },
{ 0x30, REG_MDP4_LVDS_PHY_PLL_CTRL_2 },
{ 0xc6, REG_MDP4_LVDS_PHY_PLL_CTRL_3 },
{ 0x10, REG_MDP4_LVDS_PHY_PLL_CTRL_5 },
{ 0x07, REG_MDP4_LVDS_PHY_PLL_CTRL_6 },
{ 0x62, REG_MDP4_LVDS_PHY_PLL_CTRL_7 },
{ 0x41, REG_MDP4_LVDS_PHY_PLL_CTRL_8 },
{ 0x0d, REG_MDP4_LVDS_PHY_PLL_CTRL_9 },
{ 0, 0 } }
},
};
static const struct pll_rate *find_rate(unsigned long rate)
{
int i;
for (i = 1; i < ARRAY_SIZE(freqtbl); i++)
if (rate > freqtbl[i].rate)
return &freqtbl[i-1];
return &freqtbl[i-1];
}
static int mpd4_lvds_pll_enable(struct clk_hw *hw)
{
struct mdp4_lvds_pll *lvds_pll = to_mdp4_lvds_pll(hw);
struct mdp4_kms *mdp4_kms = get_kms(lvds_pll);
const struct pll_rate *pll_rate = find_rate(lvds_pll->pixclk);
int i;
DBG("pixclk=%lu (%lu)", lvds_pll->pixclk, pll_rate->rate);
if (WARN_ON(!pll_rate))
return -EINVAL;
mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_PHY_RESET, 0x33);
for (i = 0; pll_rate->conf[i].reg; i++)
mdp4_write(mdp4_kms, pll_rate->conf[i].reg, pll_rate->conf[i].val);
mdp4_write(mdp4_kms, REG_MDP4_LVDS_PHY_PLL_CTRL_0, 0x01);
/* Wait until LVDS PLL is locked and ready */
while (!mdp4_read(mdp4_kms, REG_MDP4_LVDS_PHY_PLL_LOCKED))
cpu_relax();
return 0;
}
static void mpd4_lvds_pll_disable(struct clk_hw *hw)
{
struct mdp4_lvds_pll *lvds_pll = to_mdp4_lvds_pll(hw);
struct mdp4_kms *mdp4_kms = get_kms(lvds_pll);
DBG("");
mdp4_write(mdp4_kms, REG_MDP4_LVDS_PHY_CFG0, 0x0);
mdp4_write(mdp4_kms, REG_MDP4_LVDS_PHY_PLL_CTRL_0, 0x0);
}
static unsigned long mpd4_lvds_pll_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct mdp4_lvds_pll *lvds_pll = to_mdp4_lvds_pll(hw);
return lvds_pll->pixclk;
}
static long mpd4_lvds_pll_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
{
const struct pll_rate *pll_rate = find_rate(rate);
return pll_rate->rate;
}
static int mpd4_lvds_pll_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct mdp4_lvds_pll *lvds_pll = to_mdp4_lvds_pll(hw);
lvds_pll->pixclk = rate;
return 0;
}
static const struct clk_ops mpd4_lvds_pll_ops = {
.enable = mpd4_lvds_pll_enable,
.disable = mpd4_lvds_pll_disable,
.recalc_rate = mpd4_lvds_pll_recalc_rate,
.round_rate = mpd4_lvds_pll_round_rate,
.set_rate = mpd4_lvds_pll_set_rate,
};
static const char *mpd4_lvds_pll_parents[] = {
"pxo",
};
static struct clk_init_data pll_init = {
.name = "mpd4_lvds_pll",
.ops = &mpd4_lvds_pll_ops,
.parent_names = mpd4_lvds_pll_parents,
.num_parents = ARRAY_SIZE(mpd4_lvds_pll_parents),
};
struct clk *mpd4_lvds_pll_init(struct drm_device *dev)
{
struct mdp4_lvds_pll *lvds_pll;
struct clk *clk;
int ret;
lvds_pll = devm_kzalloc(dev->dev, sizeof(*lvds_pll), GFP_KERNEL);
if (!lvds_pll) {
ret = -ENOMEM;
goto fail;
}
lvds_pll->dev = dev;
lvds_pll->pll_hw.init = &pll_init;
clk = devm_clk_register(dev->dev, &lvds_pll->pll_hw);
if (IS_ERR(clk)) {
ret = PTR_ERR(clk);
goto fail;
}
return clk;
fail:
return ERR_PTR(ret);
}
......@@ -280,7 +280,7 @@ static int msm_load(struct drm_device *dev, unsigned long flags)
dev->mode_config.max_height = 2048;
dev->mode_config.funcs = &mode_config_funcs;
ret = drm_vblank_init(dev, 1);
ret = drm_vblank_init(dev, priv->num_crtcs);
if (ret < 0) {
dev_err(dev->dev, "failed to initialize vblank\n");
goto fail;
......@@ -315,39 +315,12 @@ static void load_gpu(struct drm_device *dev)
{
static DEFINE_MUTEX(init_lock);
struct msm_drm_private *priv = dev->dev_private;
struct msm_gpu *gpu;
mutex_lock(&init_lock);
if (priv->gpu)
goto out;
gpu = a3xx_gpu_init(dev);
if (IS_ERR(gpu)) {
dev_warn(dev->dev, "failed to load a3xx gpu\n");
gpu = NULL;
/* not fatal */
}
if (gpu) {
int ret;
mutex_lock(&dev->struct_mutex);
gpu->funcs->pm_resume(gpu);
mutex_unlock(&dev->struct_mutex);
ret = gpu->funcs->hw_init(gpu);
if (ret) {
dev_err(dev->dev, "gpu hw init failed: %d\n", ret);
gpu->funcs->destroy(gpu);
gpu = NULL;
} else {
/* give inactive pm a chance to kick in: */
msm_gpu_retire(gpu);
}
}
priv->gpu = gpu;
if (!priv->gpu)
priv->gpu = adreno_load_gpu(dev);
out:
mutex_unlock(&init_lock);
}
......@@ -1027,7 +1000,7 @@ static int __init msm_drm_register(void)
{
DBG("init");
hdmi_register();
a3xx_register();
adreno_register();
return platform_driver_register(&msm_platform_driver);
}
......@@ -1036,7 +1009,7 @@ static void __exit msm_drm_unregister(void)
DBG("fini");
platform_driver_unregister(&msm_platform_driver);
hdmi_unregister();
a3xx_unregister();
adreno_unregister();
}
module_init(msm_drm_register);
......
......@@ -166,8 +166,8 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
const char *name, const char *ioname, const char *irqname, int ringsz);
void msm_gpu_cleanup(struct msm_gpu *gpu);
struct msm_gpu *a3xx_gpu_init(struct drm_device *dev);
void __init a3xx_register(void);
void __exit a3xx_unregister(void);
struct msm_gpu *adreno_load_gpu(struct drm_device *dev);
void __init adreno_register(void);
void __exit adreno_unregister(void);
#endif /* __MSM_GPU_H__ */
......@@ -352,6 +352,30 @@ static const struct panel_desc auo_b101aw03 = {
},
};
static const struct drm_display_mode auo_b101xtn01_mode = {
.clock = 72000,
.hdisplay = 1366,
.hsync_start = 1366 + 20,
.hsync_end = 1366 + 20 + 70,
.htotal = 1366 + 20 + 70,
.vdisplay = 768,
.vsync_start = 768 + 14,
.vsync_end = 768 + 14 + 42,
.vtotal = 768 + 14 + 42,
.vrefresh = 60,
.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
};
static const struct panel_desc auo_b101xtn01 = {
.modes = &auo_b101xtn01_mode,
.num_modes = 1,
.bpc = 6,
.size = {
.width = 223,
.height = 125,
},
};
static const struct drm_display_mode auo_b133xtn01_mode = {
.clock = 69500,
.hdisplay = 1366,
......@@ -615,6 +639,9 @@ static const struct of_device_id platform_of_match[] = {
{
.compatible = "auo,b101aw03",
.data = &auo_b101aw03,
}, {
.compatible = "auo,b101xtn01",
.data = &auo_b101xtn01,
}, {
.compatible = "auo,b133htn01",
.data = &auo_b133htn01,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册