提交 8824c751 编写于 作者: D Dave Airlie

Merge tag 'omapdrm-4.14' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux into drm-next

omapdrm changes for v4.14

* HDMI hot plug IRQ support (instead of polling)
* Big driver cleanup from Laurent (no functional changes)
* OMAP5 DSI support (only the pinmuxing was missing)

* tag 'omapdrm-4.14' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux: (60 commits)
  drm/omap: Potential NULL deref in omap_crtc_duplicate_state()
  drm/omap: remove no-op cleanup code
  drm/omap: rename omapdrm device back
  drm: omapdrm: Remove omapdrm platform data
  ARM: OMAP2+: Don't register omapdss device for omapdrm
  ARM: OMAP2+: Remove unused omapdrm platform device
  drm: omapdrm: Remove the omapdss driver
  drm: omapdrm: Register omapdrm platform device in omapdss driver
  drm: omapdrm: hdmi: Don't allocate PHY features dynamically
  drm: omapdrm: hdmi: Configure the PHY from the HDMI core version
  drm: omapdrm: hdmi: Configure the PLL from the HDMI core version
  drm: omapdrm: hdmi: Pass HDMI core version as integer to HDMI audio
  drm: omapdrm: hdmi: Replace OMAP SoC model check with HDMI xmit version
  drm: omapdrm: hdmi: Rename functions and structures to use hdmi_ prefix
  drm/omap: add OMAP5 DSIPHY lane-enable support
  drm/omap: use regmap_update_bit() when muxing DSI pads
  drm: omapdrm: Remove dss_features.h
  drm: omapdrm: Move supported outputs feature to dss driver
  drm: omapdrm: Move DSS_FCK feature to dss driver
  drm: omapdrm: Move PCD, LINEWIDTH and DOWNSCALE features to dispc driver
  ...
...@@ -8,7 +8,7 @@ ccflags-y := -I$(srctree)/$(src)/include \ ...@@ -8,7 +8,7 @@ ccflags-y := -I$(srctree)/$(src)/include \
# Common support # Common support
obj-y := id.o io.o control.o devices.o fb.o timer.o pm.o \ obj-y := id.o io.o control.o devices.o fb.o timer.o pm.o \
common.o dma.o wd_timer.o display.o i2c.o hdq1w.o omap_hwmod.o \ common.o dma.o wd_timer.o display.o i2c.o hdq1w.o omap_hwmod.o \
omap_device.o omap-headsmp.o sram.o drm.o omap_device.o omap-headsmp.o sram.o
hwmod-common = omap_hwmod.o omap_hwmod_reset.o \ hwmod-common = omap_hwmod.o omap_hwmod_reset.o \
omap_hwmod_common_data.o omap_hwmod_common_data.o
......
...@@ -33,6 +33,7 @@ static void __init __maybe_unused omap_generic_init(void) ...@@ -33,6 +33,7 @@ static void __init __maybe_unused omap_generic_init(void)
pdata_quirks_init(omap_dt_match_table); pdata_quirks_init(omap_dt_match_table);
omapdss_init_of(); omapdss_init_of();
omap_soc_device_init();
} }
#ifdef CONFIG_SOC_OMAP2420 #ifdef CONFIG_SOC_OMAP2420
......
...@@ -66,6 +66,7 @@ ...@@ -66,6 +66,7 @@
*/ */
#define FRAMEDONE_IRQ_TIMEOUT 100 #define FRAMEDONE_IRQ_TIMEOUT 100
#if defined(CONFIG_FB_OMAP2)
static struct platform_device omap_display_device = { static struct platform_device omap_display_device = {
.name = "omapdss", .name = "omapdss",
.id = -1, .id = -1,
...@@ -163,6 +164,64 @@ static enum omapdss_version __init omap_display_get_version(void) ...@@ -163,6 +164,64 @@ static enum omapdss_version __init omap_display_get_version(void)
return OMAPDSS_VER_UNKNOWN; return OMAPDSS_VER_UNKNOWN;
} }
static int __init omapdss_init_fbdev(void)
{
static struct omap_dss_board_info board_data = {
.dsi_enable_pads = omap_dsi_enable_pads,
.dsi_disable_pads = omap_dsi_disable_pads,
.set_min_bus_tput = omap_dss_set_min_bus_tput,
};
struct device_node *node;
board_data.version = omap_display_get_version();
if (board_data.version == OMAPDSS_VER_UNKNOWN) {
pr_err("DSS not supported on this SoC\n");
return -ENODEV;
}
omap_display_device.dev.platform_data = &board_data;
r = platform_device_register(&omap_display_device);
if (r < 0) {
pr_err("Unable to register omapdss device\n");
return r;
}
/* create vrfb device */
r = omap_init_vrfb();
if (r < 0) {
pr_err("Unable to register omapvrfb device\n");
return r;
}
/* create FB device */
r = omap_init_fb();
if (r < 0) {
pr_err("Unable to register omapfb device\n");
return r;
}
/* create V4L2 display device */
r = omap_init_vout();
if (r < 0) {
pr_err("Unable to register omap_vout device\n");
return r;
}
/* add DSI info for omap4 */
node = of_find_node_by_name(NULL, "omap4_padconf_global");
if (node)
omap4_dsi_mux_syscon = syscon_node_to_regmap(node);
return 0;
}
#else
static inline int omapdss_init_fbdev(void)
{
return 0;
}
#endif /* CONFIG_FB_OMAP2 */
static void dispc_disable_outputs(void) static void dispc_disable_outputs(void)
{ {
u32 v, irq_mask = 0; u32 v, irq_mask = 0;
...@@ -335,16 +394,9 @@ static struct device_node * __init omapdss_find_dss_of_node(void) ...@@ -335,16 +394,9 @@ static struct device_node * __init omapdss_find_dss_of_node(void)
int __init omapdss_init_of(void) int __init omapdss_init_of(void)
{ {
int r; int r;
enum omapdss_version ver;
struct device_node *node; struct device_node *node;
struct platform_device *pdev; struct platform_device *pdev;
static struct omap_dss_board_info board_data = {
.dsi_enable_pads = omap_dsi_enable_pads,
.dsi_disable_pads = omap_dsi_disable_pads,
.set_min_bus_tput = omap_dss_set_min_bus_tput,
};
/* only create dss helper devices if dss is enabled in the .dts */ /* only create dss helper devices if dss is enabled in the .dts */
node = omapdss_find_dss_of_node(); node = omapdss_find_dss_of_node();
...@@ -354,13 +406,6 @@ int __init omapdss_init_of(void) ...@@ -354,13 +406,6 @@ int __init omapdss_init_of(void)
if (!of_device_is_available(node)) if (!of_device_is_available(node))
return 0; return 0;
ver = omap_display_get_version();
if (ver == OMAPDSS_VER_UNKNOWN) {
pr_err("DSS not supported on this SoC\n");
return -ENODEV;
}
pdev = of_find_device_by_node(node); pdev = of_find_device_by_node(node);
if (!pdev) { if (!pdev) {
...@@ -374,48 +419,5 @@ int __init omapdss_init_of(void) ...@@ -374,48 +419,5 @@ int __init omapdss_init_of(void)
return r; return r;
} }
board_data.version = ver; return omapdss_init_fbdev();
omap_display_device.dev.platform_data = &board_data;
r = platform_device_register(&omap_display_device);
if (r < 0) {
pr_err("Unable to register omapdss device\n");
return r;
}
/* create DRM device */
r = omap_init_drm();
if (r < 0) {
pr_err("Unable to register omapdrm device\n");
return r;
}
/* create vrfb device */
r = omap_init_vrfb();
if (r < 0) {
pr_err("Unable to register omapvrfb device\n");
return r;
}
/* create FB device */
r = omap_init_fb();
if (r < 0) {
pr_err("Unable to register omapfb device\n");
return r;
}
/* create V4L2 display device */
r = omap_init_vout();
if (r < 0) {
pr_err("Unable to register omap_vout device\n");
return r;
}
/* add DSI info for omap4 */
node = of_find_node_by_name(NULL, "omap4_padconf_global");
if (node)
omap4_dsi_mux_syscon = syscon_node_to_regmap(node);
return 0;
} }
...@@ -26,7 +26,6 @@ struct omap_dss_dispc_dev_attr { ...@@ -26,7 +26,6 @@ struct omap_dss_dispc_dev_attr {
bool has_framedonetv_irq; bool has_framedonetv_irq;
}; };
int omap_init_drm(void);
int omap_init_vrfb(void); int omap_init_vrfb(void);
int omap_init_fb(void); int omap_init_fb(void);
int omap_init_vout(void); int omap_init_vout(void);
......
/*
* DRM/KMS device registration for TI OMAP platforms
*
* Copyright (C) 2012 Texas Instruments
* Author: Rob Clark <rob.clark@linaro.org>
*
* 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/module.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/platform_data/omap_drm.h>
#include "soc.h"
#include "display.h"
#if IS_ENABLED(CONFIG_DRM_OMAP)
static struct omap_drm_platform_data platform_data;
static struct platform_device omap_drm_device = {
.dev = {
.coherent_dma_mask = DMA_BIT_MASK(32),
.platform_data = &platform_data,
},
.name = "omapdrm",
.id = 0,
};
int __init omap_init_drm(void)
{
platform_data.omaprev = GET_OMAP_TYPE;
return platform_device_register(&omap_drm_device);
}
#else
int __init omap_init_drm(void) { return 0; }
#endif
...@@ -428,7 +428,6 @@ static void __init __maybe_unused omap_hwmod_init_postsetup(void) ...@@ -428,7 +428,6 @@ static void __init __maybe_unused omap_hwmod_init_postsetup(void)
static void __init __maybe_unused omap_common_late_init(void) static void __init __maybe_unused omap_common_late_init(void)
{ {
omap2_common_pm_late_init(); omap2_common_pm_late_init();
omap_soc_device_init();
} }
#ifdef CONFIG_SOC_OMAP2420 #ifdef CONFIG_SOC_OMAP2420
......
...@@ -198,6 +198,9 @@ static int tvc_probe(struct platform_device *pdev) ...@@ -198,6 +198,9 @@ static int tvc_probe(struct platform_device *pdev)
struct omap_dss_device *dssdev; struct omap_dss_device *dssdev;
int r; int r;
if (!pdev->dev.of_node)
return -ENODEV;
ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
if (!ddata) if (!ddata)
return -ENOMEM; return -ENOMEM;
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_gpio.h> #include <linux/of_gpio.h>
#include <linux/mutex.h>
#include <drm/drm_edid.h> #include <drm/drm_edid.h>
...@@ -37,6 +38,10 @@ static const struct videomode hdmic_default_vm = { ...@@ -37,6 +38,10 @@ static const struct videomode hdmic_default_vm = {
struct panel_drv_data { struct panel_drv_data {
struct omap_dss_device dssdev; struct omap_dss_device dssdev;
struct omap_dss_device *in; struct omap_dss_device *in;
void (*hpd_cb)(void *cb_data, enum drm_connector_status status);
void *hpd_cb_data;
bool hpd_enabled;
struct mutex hpd_lock;
struct device *dev; struct device *dev;
...@@ -167,6 +172,70 @@ static bool hdmic_detect(struct omap_dss_device *dssdev) ...@@ -167,6 +172,70 @@ static bool hdmic_detect(struct omap_dss_device *dssdev)
return in->ops.hdmi->detect(in); return in->ops.hdmi->detect(in);
} }
static int hdmic_register_hpd_cb(struct omap_dss_device *dssdev,
void (*cb)(void *cb_data,
enum drm_connector_status status),
void *cb_data)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
if (gpio_is_valid(ddata->hpd_gpio)) {
mutex_lock(&ddata->hpd_lock);
ddata->hpd_cb = cb;
ddata->hpd_cb_data = cb_data;
mutex_unlock(&ddata->hpd_lock);
return 0;
} else if (in->ops.hdmi->register_hpd_cb) {
return in->ops.hdmi->register_hpd_cb(in, cb, cb_data);
}
return -ENOTSUPP;
}
static void hdmic_unregister_hpd_cb(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
if (gpio_is_valid(ddata->hpd_gpio)) {
mutex_lock(&ddata->hpd_lock);
ddata->hpd_cb = NULL;
ddata->hpd_cb_data = NULL;
mutex_unlock(&ddata->hpd_lock);
} else if (in->ops.hdmi->unregister_hpd_cb) {
in->ops.hdmi->unregister_hpd_cb(in);
}
}
static void hdmic_enable_hpd(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
if (gpio_is_valid(ddata->hpd_gpio)) {
mutex_lock(&ddata->hpd_lock);
ddata->hpd_enabled = true;
mutex_unlock(&ddata->hpd_lock);
} else if (in->ops.hdmi->enable_hpd) {
in->ops.hdmi->enable_hpd(in);
}
}
static void hdmic_disable_hpd(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
if (gpio_is_valid(ddata->hpd_gpio)) {
mutex_lock(&ddata->hpd_lock);
ddata->hpd_enabled = false;
mutex_unlock(&ddata->hpd_lock);
} else if (in->ops.hdmi->disable_hpd) {
in->ops.hdmi->disable_hpd(in);
}
}
static int hdmic_set_hdmi_mode(struct omap_dss_device *dssdev, bool hdmi_mode) static int hdmic_set_hdmi_mode(struct omap_dss_device *dssdev, bool hdmi_mode)
{ {
struct panel_drv_data *ddata = to_panel_data(dssdev); struct panel_drv_data *ddata = to_panel_data(dssdev);
...@@ -197,10 +266,34 @@ static struct omap_dss_driver hdmic_driver = { ...@@ -197,10 +266,34 @@ static struct omap_dss_driver hdmic_driver = {
.read_edid = hdmic_read_edid, .read_edid = hdmic_read_edid,
.detect = hdmic_detect, .detect = hdmic_detect,
.register_hpd_cb = hdmic_register_hpd_cb,
.unregister_hpd_cb = hdmic_unregister_hpd_cb,
.enable_hpd = hdmic_enable_hpd,
.disable_hpd = hdmic_disable_hpd,
.set_hdmi_mode = hdmic_set_hdmi_mode, .set_hdmi_mode = hdmic_set_hdmi_mode,
.set_hdmi_infoframe = hdmic_set_infoframe, .set_hdmi_infoframe = hdmic_set_infoframe,
}; };
static irqreturn_t hdmic_hpd_isr(int irq, void *data)
{
struct panel_drv_data *ddata = data;
mutex_lock(&ddata->hpd_lock);
if (ddata->hpd_enabled && ddata->hpd_cb) {
enum drm_connector_status status;
if (hdmic_detect(&ddata->dssdev))
status = connector_status_connected;
else
status = connector_status_disconnected;
ddata->hpd_cb(ddata->hpd_cb_data, status);
}
mutex_unlock(&ddata->hpd_lock);
return IRQ_HANDLED;
}
static int hdmic_probe_of(struct platform_device *pdev) static int hdmic_probe_of(struct platform_device *pdev)
{ {
struct panel_drv_data *ddata = platform_get_drvdata(pdev); struct panel_drv_data *ddata = platform_get_drvdata(pdev);
...@@ -246,11 +339,22 @@ static int hdmic_probe(struct platform_device *pdev) ...@@ -246,11 +339,22 @@ static int hdmic_probe(struct platform_device *pdev)
if (r) if (r)
return r; return r;
mutex_init(&ddata->hpd_lock);
if (gpio_is_valid(ddata->hpd_gpio)) { if (gpio_is_valid(ddata->hpd_gpio)) {
r = devm_gpio_request_one(&pdev->dev, ddata->hpd_gpio, r = devm_gpio_request_one(&pdev->dev, ddata->hpd_gpio,
GPIOF_DIR_IN, "hdmi_hpd"); GPIOF_DIR_IN, "hdmi_hpd");
if (r) if (r)
goto err_reg; goto err_reg;
r = devm_request_threaded_irq(&pdev->dev,
gpio_to_irq(ddata->hpd_gpio),
NULL, hdmic_hpd_isr,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
IRQF_ONESHOT,
"hdmic hpd", ddata);
if (r)
goto err_reg;
} }
ddata->vm = hdmic_default_vm; ddata->vm = hdmic_default_vm;
......
...@@ -15,12 +15,17 @@ ...@@ -15,12 +15,17 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/gpio/consumer.h> #include <linux/gpio/consumer.h>
#include <linux/mutex.h>
#include "../dss/omapdss.h" #include "../dss/omapdss.h"
struct panel_drv_data { struct panel_drv_data {
struct omap_dss_device dssdev; struct omap_dss_device dssdev;
struct omap_dss_device *in; struct omap_dss_device *in;
void (*hpd_cb)(void *cb_data, enum drm_connector_status status);
void *hpd_cb_data;
bool hpd_enabled;
struct mutex hpd_lock;
struct gpio_desc *ct_cp_hpd_gpio; struct gpio_desc *ct_cp_hpd_gpio;
struct gpio_desc *ls_oe_gpio; struct gpio_desc *ls_oe_gpio;
...@@ -162,6 +167,49 @@ static bool tpd_detect(struct omap_dss_device *dssdev) ...@@ -162,6 +167,49 @@ static bool tpd_detect(struct omap_dss_device *dssdev)
return gpiod_get_value_cansleep(ddata->hpd_gpio); return gpiod_get_value_cansleep(ddata->hpd_gpio);
} }
static int tpd_register_hpd_cb(struct omap_dss_device *dssdev,
void (*cb)(void *cb_data,
enum drm_connector_status status),
void *cb_data)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
mutex_lock(&ddata->hpd_lock);
ddata->hpd_cb = cb;
ddata->hpd_cb_data = cb_data;
mutex_unlock(&ddata->hpd_lock);
return 0;
}
static void tpd_unregister_hpd_cb(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
mutex_lock(&ddata->hpd_lock);
ddata->hpd_cb = NULL;
ddata->hpd_cb_data = NULL;
mutex_unlock(&ddata->hpd_lock);
}
static void tpd_enable_hpd(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
mutex_lock(&ddata->hpd_lock);
ddata->hpd_enabled = true;
mutex_unlock(&ddata->hpd_lock);
}
static void tpd_disable_hpd(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
mutex_lock(&ddata->hpd_lock);
ddata->hpd_enabled = false;
mutex_unlock(&ddata->hpd_lock);
}
static int tpd_set_infoframe(struct omap_dss_device *dssdev, static int tpd_set_infoframe(struct omap_dss_device *dssdev,
const struct hdmi_avi_infoframe *avi) const struct hdmi_avi_infoframe *avi)
{ {
...@@ -193,10 +241,34 @@ static const struct omapdss_hdmi_ops tpd_hdmi_ops = { ...@@ -193,10 +241,34 @@ static const struct omapdss_hdmi_ops tpd_hdmi_ops = {
.read_edid = tpd_read_edid, .read_edid = tpd_read_edid,
.detect = tpd_detect, .detect = tpd_detect,
.register_hpd_cb = tpd_register_hpd_cb,
.unregister_hpd_cb = tpd_unregister_hpd_cb,
.enable_hpd = tpd_enable_hpd,
.disable_hpd = tpd_disable_hpd,
.set_infoframe = tpd_set_infoframe, .set_infoframe = tpd_set_infoframe,
.set_hdmi_mode = tpd_set_hdmi_mode, .set_hdmi_mode = tpd_set_hdmi_mode,
}; };
static irqreturn_t tpd_hpd_isr(int irq, void *data)
{
struct panel_drv_data *ddata = data;
mutex_lock(&ddata->hpd_lock);
if (ddata->hpd_enabled && ddata->hpd_cb) {
enum drm_connector_status status;
if (tpd_detect(&ddata->dssdev))
status = connector_status_connected;
else
status = connector_status_disconnected;
ddata->hpd_cb(ddata->hpd_cb_data, status);
}
mutex_unlock(&ddata->hpd_lock);
return IRQ_HANDLED;
}
static int tpd_probe_of(struct platform_device *pdev) static int tpd_probe_of(struct platform_device *pdev)
{ {
struct panel_drv_data *ddata = platform_get_drvdata(pdev); struct panel_drv_data *ddata = platform_get_drvdata(pdev);
...@@ -261,6 +333,15 @@ static int tpd_probe(struct platform_device *pdev) ...@@ -261,6 +333,15 @@ static int tpd_probe(struct platform_device *pdev)
ddata->hpd_gpio = gpio; ddata->hpd_gpio = gpio;
mutex_init(&ddata->hpd_lock);
r = devm_request_threaded_irq(&pdev->dev, gpiod_to_irq(ddata->hpd_gpio),
NULL, tpd_hpd_isr,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"tpd12s015 hpd", ddata);
if (r)
goto err_gpio;
dssdev = &ddata->dssdev; dssdev = &ddata->dssdev;
dssdev->ops.hdmi = &tpd_hdmi_ops; dssdev->ops.hdmi = &tpd_hdmi_ops;
dssdev->dev = &pdev->dev; dssdev->dev = &pdev->dev;
......
...@@ -231,6 +231,9 @@ static int panel_dpi_probe(struct platform_device *pdev) ...@@ -231,6 +231,9 @@ static int panel_dpi_probe(struct platform_device *pdev)
struct omap_dss_device *dssdev; struct omap_dss_device *dssdev;
int r; int r;
if (!pdev->dev.of_node)
return -ENODEV;
ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
if (ddata == NULL) if (ddata == NULL)
return -ENOMEM; return -ENOMEM;
......
...@@ -554,7 +554,7 @@ static struct attribute *dsicm_attrs[] = { ...@@ -554,7 +554,7 @@ static struct attribute *dsicm_attrs[] = {
NULL, NULL,
}; };
static struct attribute_group dsicm_attr_group = { static const struct attribute_group dsicm_attr_group = {
.attrs = dsicm_attrs, .attrs = dsicm_attrs,
}; };
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
#include "../dss/omapdss.h" #include "../dss/omapdss.h"
static struct videomode lb035q02_vm = { static const struct videomode lb035q02_vm = {
.hactive = 320, .hactive = 320,
.vactive = 240, .vactive = 240,
......
...@@ -503,7 +503,7 @@ static struct attribute *bldev_attrs[] = { ...@@ -503,7 +503,7 @@ static struct attribute *bldev_attrs[] = {
NULL, NULL,
}; };
static struct attribute_group bldev_attr_group = { static const struct attribute_group bldev_attr_group = {
.attrs = bldev_attrs, .attrs = bldev_attrs,
}; };
...@@ -720,6 +720,9 @@ static int acx565akm_probe(struct spi_device *spi) ...@@ -720,6 +720,9 @@ static int acx565akm_probe(struct spi_device *spi)
dev_dbg(&spi->dev, "%s\n", __func__); dev_dbg(&spi->dev, "%s\n", __func__);
if (!spi->dev.of_node)
return -ENODEV;
spi->mode = SPI_MODE_3; spi->mode = SPI_MODE_3;
ddata = devm_kzalloc(&spi->dev, sizeof(*ddata), GFP_KERNEL); ddata = devm_kzalloc(&spi->dev, sizeof(*ddata), GFP_KERNEL);
......
...@@ -40,7 +40,7 @@ struct panel_drv_data { ...@@ -40,7 +40,7 @@ struct panel_drv_data {
struct spi_device *spi_dev; struct spi_device *spi_dev;
}; };
static struct videomode td028ttec1_panel_vm = { static const struct videomode td028ttec1_panel_vm = {
.hactive = 480, .hactive = 480,
.vactive = 640, .vactive = 640,
.pixelclock = 22153000, .pixelclock = 22153000,
......
...@@ -282,7 +282,7 @@ static struct attribute *tpo_td043_attrs[] = { ...@@ -282,7 +282,7 @@ static struct attribute *tpo_td043_attrs[] = {
NULL, NULL,
}; };
static struct attribute_group tpo_td043_attr_group = { static const struct attribute_group tpo_td043_attr_group = {
.attrs = tpo_td043_attrs, .attrs = tpo_td043_attrs,
}; };
......
...@@ -5,7 +5,7 @@ omapdss-base-y := base.o display.o dss-of.o output.o ...@@ -5,7 +5,7 @@ omapdss-base-y := base.o display.o dss-of.o output.o
obj-$(CONFIG_OMAP2_DSS) += omapdss.o obj-$(CONFIG_OMAP2_DSS) += omapdss.o
# Core DSS files # Core DSS files
omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o \ omapdss-y := core.o dss.o dispc.o dispc_coefs.o \
pll.o video-pll.o pll.o video-pll.o
omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o
omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o
......
...@@ -24,182 +24,10 @@ ...@@ -24,182 +24,10 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/seq_file.h>
#include <linux/debugfs.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/regulator/consumer.h>
#include <linux/suspend.h>
#include <linux/slab.h>
#include "omapdss.h" #include "omapdss.h"
#include "dss.h" #include "dss.h"
#include "dss_features.h"
static struct {
struct platform_device *pdev;
} core;
enum omapdss_version omapdss_get_version(void)
{
struct omap_dss_board_info *pdata = core.pdev->dev.platform_data;
return pdata->version;
}
EXPORT_SYMBOL(omapdss_get_version);
int dss_dsi_enable_pads(int dsi_id, unsigned lane_mask)
{
struct omap_dss_board_info *board_data = core.pdev->dev.platform_data;
if (!board_data->dsi_enable_pads)
return -ENOENT;
return board_data->dsi_enable_pads(dsi_id, lane_mask);
}
void dss_dsi_disable_pads(int dsi_id, unsigned lane_mask)
{
struct omap_dss_board_info *board_data = core.pdev->dev.platform_data;
if (!board_data->dsi_disable_pads)
return;
return board_data->dsi_disable_pads(dsi_id, lane_mask);
}
int dss_set_min_bus_tput(struct device *dev, unsigned long tput)
{
struct omap_dss_board_info *pdata = core.pdev->dev.platform_data;
if (pdata->set_min_bus_tput)
return pdata->set_min_bus_tput(dev, tput);
else
return 0;
}
#if defined(CONFIG_OMAP2_DSS_DEBUGFS)
static int dss_debug_show(struct seq_file *s, void *unused)
{
void (*func)(struct seq_file *) = s->private;
func(s);
return 0;
}
static int dss_debug_open(struct inode *inode, struct file *file)
{
return single_open(file, dss_debug_show, inode->i_private);
}
static const struct file_operations dss_debug_fops = {
.open = dss_debug_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static struct dentry *dss_debugfs_dir;
static int dss_initialize_debugfs(void)
{
dss_debugfs_dir = debugfs_create_dir("omapdss", NULL);
if (IS_ERR(dss_debugfs_dir)) {
int err = PTR_ERR(dss_debugfs_dir);
dss_debugfs_dir = NULL;
return err;
}
debugfs_create_file("clk", S_IRUGO, dss_debugfs_dir,
&dss_debug_dump_clocks, &dss_debug_fops);
return 0;
}
static void dss_uninitialize_debugfs(void)
{
if (dss_debugfs_dir)
debugfs_remove_recursive(dss_debugfs_dir);
}
int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *))
{
struct dentry *d;
d = debugfs_create_file(name, S_IRUGO, dss_debugfs_dir,
write, &dss_debug_fops);
return PTR_ERR_OR_ZERO(d);
}
#else /* CONFIG_OMAP2_DSS_DEBUGFS */
static inline int dss_initialize_debugfs(void)
{
return 0;
}
static inline void dss_uninitialize_debugfs(void)
{
}
int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *))
{
return 0;
}
#endif /* CONFIG_OMAP2_DSS_DEBUGFS */
/* PLATFORM DEVICE */
static void dss_disable_all_devices(void)
{
struct omap_dss_device *dssdev = NULL;
for_each_dss_dev(dssdev) {
if (!dssdev->driver)
continue;
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
dssdev->driver->disable(dssdev);
}
}
static int __init omap_dss_probe(struct platform_device *pdev)
{
int r;
core.pdev = pdev;
dss_features_init(omapdss_get_version());
r = dss_initialize_debugfs();
if (r)
goto err_debugfs;
return 0;
err_debugfs:
return r;
}
static int omap_dss_remove(struct platform_device *pdev)
{
dss_uninitialize_debugfs();
return 0;
}
static void omap_dss_shutdown(struct platform_device *pdev)
{
DSSDBG("shutdown\n");
dss_disable_all_devices();
}
static struct platform_driver omap_dss_driver = {
.remove = omap_dss_remove,
.shutdown = omap_dss_shutdown,
.driver = {
.name = "omapdss",
},
};
/* INIT */ /* INIT */
static int (*dss_output_drv_reg_funcs[])(void) __initdata = { static int (*dss_output_drv_reg_funcs[])(void) __initdata = {
...@@ -236,21 +64,25 @@ static void (*dss_output_drv_unreg_funcs[])(void) = { ...@@ -236,21 +64,25 @@ static void (*dss_output_drv_unreg_funcs[])(void) = {
dss_uninit_platform_driver, dss_uninit_platform_driver,
}; };
static struct platform_device *omap_drm_device;
static int __init omap_dss_init(void) static int __init omap_dss_init(void)
{ {
int r; int r;
int i; int i;
r = platform_driver_probe(&omap_dss_driver, omap_dss_probe);
if (r)
return r;
for (i = 0; i < ARRAY_SIZE(dss_output_drv_reg_funcs); ++i) { for (i = 0; i < ARRAY_SIZE(dss_output_drv_reg_funcs); ++i) {
r = dss_output_drv_reg_funcs[i](); r = dss_output_drv_reg_funcs[i]();
if (r) if (r)
goto err_reg; goto err_reg;
} }
omap_drm_device = platform_device_register_simple("omapdrm", 0, NULL, 0);
if (IS_ERR(omap_drm_device)) {
r = PTR_ERR(omap_drm_device);
goto err_reg;
}
return 0; return 0;
err_reg: err_reg:
...@@ -259,8 +91,6 @@ static int __init omap_dss_init(void) ...@@ -259,8 +91,6 @@ static int __init omap_dss_init(void)
++i) ++i)
dss_output_drv_unreg_funcs[i](); dss_output_drv_unreg_funcs[i]();
platform_driver_unregister(&omap_dss_driver);
return r; return r;
} }
...@@ -268,10 +98,10 @@ static void __exit omap_dss_exit(void) ...@@ -268,10 +98,10 @@ static void __exit omap_dss_exit(void)
{ {
int i; int i;
platform_device_unregister(omap_drm_device);
for (i = 0; i < ARRAY_SIZE(dss_output_drv_unreg_funcs); ++i) for (i = 0; i < ARRAY_SIZE(dss_output_drv_unreg_funcs); ++i)
dss_output_drv_unreg_funcs[i](); dss_output_drv_unreg_funcs[i]();
platform_driver_unregister(&omap_dss_driver);
} }
module_init(omap_dss_init); module_init(omap_dss_init);
......
此差异已折叠。
...@@ -32,13 +32,14 @@ ...@@ -32,13 +32,14 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/sys_soc.h>
#include "omapdss.h" #include "omapdss.h"
#include "dss.h" #include "dss.h"
#include "dss_features.h"
struct dpi_data { struct dpi_data {
struct platform_device *pdev; struct platform_device *pdev;
enum dss_model dss_model;
struct regulator *vdds_dsi_reg; struct regulator *vdds_dsi_reg;
enum dss_clk_source clk_src; enum dss_clk_source clk_src;
...@@ -99,25 +100,21 @@ static enum dss_clk_source dpi_get_clk_src_dra7xx(enum omap_channel channel) ...@@ -99,25 +100,21 @@ static enum dss_clk_source dpi_get_clk_src_dra7xx(enum omap_channel channel)
return DSS_CLK_SRC_FCK; return DSS_CLK_SRC_FCK;
} }
static enum dss_clk_source dpi_get_clk_src(enum omap_channel channel) static enum dss_clk_source dpi_get_clk_src(struct dpi_data *dpi)
{ {
enum omap_channel channel = dpi->output.dispc_channel;
/* /*
* XXX we can't currently use DSI PLL for DPI with OMAP3, as the DSI PLL * XXX we can't currently use DSI PLL for DPI with OMAP3, as the DSI PLL
* would also be used for DISPC fclk. Meaning, when the DPI output is * would also be used for DISPC fclk. Meaning, when the DPI output is
* disabled, DISPC clock will be disabled, and TV out will stop. * disabled, DISPC clock will be disabled, and TV out will stop.
*/ */
switch (omapdss_get_version()) { switch (dpi->dss_model) {
case OMAPDSS_VER_OMAP24xx: case DSS_MODEL_OMAP2:
case OMAPDSS_VER_OMAP34xx_ES1: case DSS_MODEL_OMAP3:
case OMAPDSS_VER_OMAP34xx_ES3:
case OMAPDSS_VER_OMAP3630:
case OMAPDSS_VER_AM35xx:
case OMAPDSS_VER_AM43xx:
return DSS_CLK_SRC_FCK; return DSS_CLK_SRC_FCK;
case OMAPDSS_VER_OMAP4430_ES1: case DSS_MODEL_OMAP4:
case OMAPDSS_VER_OMAP4430_ES2:
case OMAPDSS_VER_OMAP4:
switch (channel) { switch (channel) {
case OMAP_DSS_CHANNEL_LCD: case OMAP_DSS_CHANNEL_LCD:
return DSS_CLK_SRC_PLL1_1; return DSS_CLK_SRC_PLL1_1;
...@@ -127,7 +124,7 @@ static enum dss_clk_source dpi_get_clk_src(enum omap_channel channel) ...@@ -127,7 +124,7 @@ static enum dss_clk_source dpi_get_clk_src(enum omap_channel channel)
return DSS_CLK_SRC_FCK; return DSS_CLK_SRC_FCK;
} }
case OMAPDSS_VER_OMAP5: case DSS_MODEL_OMAP5:
switch (channel) { switch (channel) {
case OMAP_DSS_CHANNEL_LCD: case OMAP_DSS_CHANNEL_LCD:
return DSS_CLK_SRC_PLL1_1; return DSS_CLK_SRC_PLL1_1;
...@@ -138,7 +135,7 @@ static enum dss_clk_source dpi_get_clk_src(enum omap_channel channel) ...@@ -138,7 +135,7 @@ static enum dss_clk_source dpi_get_clk_src(enum omap_channel channel)
return DSS_CLK_SRC_FCK; return DSS_CLK_SRC_FCK;
} }
case OMAPDSS_VER_DRA7xx: case DSS_MODEL_DRA7:
return dpi_get_clk_src_dra7xx(channel); return dpi_get_clk_src_dra7xx(channel);
default: default:
...@@ -213,7 +210,7 @@ static bool dpi_calc_pll_cb(int n, int m, unsigned long fint, ...@@ -213,7 +210,7 @@ static bool dpi_calc_pll_cb(int n, int m, unsigned long fint,
ctx->pll_cinfo.clkdco = clkdco; ctx->pll_cinfo.clkdco = clkdco;
return dss_pll_hsdiv_calc_a(ctx->pll, clkdco, return dss_pll_hsdiv_calc_a(ctx->pll, clkdco,
ctx->pck_min, dss_feat_get_param_max(FEAT_PARAM_DSS_FCK), ctx->pck_min, dss_get_max_fck_rate(),
dpi_calc_hsdiv_cb, ctx); dpi_calc_hsdiv_cb, ctx);
} }
...@@ -403,19 +400,13 @@ static int dpi_display_enable(struct omap_dss_device *dssdev) ...@@ -403,19 +400,13 @@ static int dpi_display_enable(struct omap_dss_device *dssdev)
mutex_lock(&dpi->lock); mutex_lock(&dpi->lock);
if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && !dpi->vdds_dsi_reg) {
DSSERR("no VDSS_DSI regulator\n");
r = -ENODEV;
goto err_no_reg;
}
if (!out->dispc_channel_connected) { if (!out->dispc_channel_connected) {
DSSERR("failed to enable display: no output/manager\n"); DSSERR("failed to enable display: no output/manager\n");
r = -ENODEV; r = -ENODEV;
goto err_no_out_mgr; goto err_no_out_mgr;
} }
if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) { if (dpi->vdds_dsi_reg) {
r = regulator_enable(dpi->vdds_dsi_reg); r = regulator_enable(dpi->vdds_dsi_reg);
if (r) if (r)
goto err_reg_enable; goto err_reg_enable;
...@@ -459,11 +450,10 @@ static int dpi_display_enable(struct omap_dss_device *dssdev) ...@@ -459,11 +450,10 @@ static int dpi_display_enable(struct omap_dss_device *dssdev)
err_src_sel: err_src_sel:
dispc_runtime_put(); dispc_runtime_put();
err_get_dispc: err_get_dispc:
if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) if (dpi->vdds_dsi_reg)
regulator_disable(dpi->vdds_dsi_reg); regulator_disable(dpi->vdds_dsi_reg);
err_reg_enable: err_reg_enable:
err_no_out_mgr: err_no_out_mgr:
err_no_reg:
mutex_unlock(&dpi->lock); mutex_unlock(&dpi->lock);
return r; return r;
} }
...@@ -484,7 +474,7 @@ static void dpi_display_disable(struct omap_dss_device *dssdev) ...@@ -484,7 +474,7 @@ static void dpi_display_disable(struct omap_dss_device *dssdev)
dispc_runtime_put(); dispc_runtime_put();
if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) if (dpi->vdds_dsi_reg)
regulator_disable(dpi->vdds_dsi_reg); regulator_disable(dpi->vdds_dsi_reg);
mutex_unlock(&dpi->lock); mutex_unlock(&dpi->lock);
...@@ -575,11 +565,21 @@ static int dpi_verify_pll(struct dss_pll *pll) ...@@ -575,11 +565,21 @@ static int dpi_verify_pll(struct dss_pll *pll)
return 0; return 0;
} }
static const struct soc_device_attribute dpi_soc_devices[] = {
{ .family = "OMAP3[456]*" },
{ .family = "[AD]M37*" },
{ /* sentinel */ }
};
static int dpi_init_regulator(struct dpi_data *dpi) static int dpi_init_regulator(struct dpi_data *dpi)
{ {
struct regulator *vdds_dsi; struct regulator *vdds_dsi;
if (!dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) /*
* The DPI uses the DSI VDDS on OMAP34xx, OMAP35xx, OMAP36xx, AM37xx and
* DM37xx only.
*/
if (!soc_device_match(dpi_soc_devices))
return 0; return 0;
if (dpi->vdds_dsi_reg) if (dpi->vdds_dsi_reg)
...@@ -604,7 +604,7 @@ static void dpi_init_pll(struct dpi_data *dpi) ...@@ -604,7 +604,7 @@ static void dpi_init_pll(struct dpi_data *dpi)
if (dpi->pll) if (dpi->pll)
return; return;
dpi->clk_src = dpi_get_clk_src(dpi->output.dispc_channel); dpi->clk_src = dpi_get_clk_src(dpi);
pll = dss_pll_find_by_src(dpi->clk_src); pll = dss_pll_find_by_src(dpi->clk_src);
if (!pll) if (!pll)
...@@ -624,18 +624,14 @@ static void dpi_init_pll(struct dpi_data *dpi) ...@@ -624,18 +624,14 @@ static void dpi_init_pll(struct dpi_data *dpi)
* the channel in some more dynamic manner, or get the channel as a user * the channel in some more dynamic manner, or get the channel as a user
* parameter. * parameter.
*/ */
static enum omap_channel dpi_get_channel(int port_num) static enum omap_channel dpi_get_channel(struct dpi_data *dpi, int port_num)
{ {
switch (omapdss_get_version()) { switch (dpi->dss_model) {
case OMAPDSS_VER_OMAP24xx: case DSS_MODEL_OMAP2:
case OMAPDSS_VER_OMAP34xx_ES1: case DSS_MODEL_OMAP3:
case OMAPDSS_VER_OMAP34xx_ES3:
case OMAPDSS_VER_OMAP3630:
case OMAPDSS_VER_AM35xx:
case OMAPDSS_VER_AM43xx:
return OMAP_DSS_CHANNEL_LCD; return OMAP_DSS_CHANNEL_LCD;
case OMAPDSS_VER_DRA7xx: case DSS_MODEL_DRA7:
switch (port_num) { switch (port_num) {
case 2: case 2:
return OMAP_DSS_CHANNEL_LCD3; return OMAP_DSS_CHANNEL_LCD3;
...@@ -646,12 +642,10 @@ static enum omap_channel dpi_get_channel(int port_num) ...@@ -646,12 +642,10 @@ static enum omap_channel dpi_get_channel(int port_num)
return OMAP_DSS_CHANNEL_LCD; return OMAP_DSS_CHANNEL_LCD;
} }
case OMAPDSS_VER_OMAP4430_ES1: case DSS_MODEL_OMAP4:
case OMAPDSS_VER_OMAP4430_ES2:
case OMAPDSS_VER_OMAP4:
return OMAP_DSS_CHANNEL_LCD2; return OMAP_DSS_CHANNEL_LCD2;
case OMAPDSS_VER_OMAP5: case DSS_MODEL_OMAP5:
return OMAP_DSS_CHANNEL_LCD3; return OMAP_DSS_CHANNEL_LCD3;
default: default:
...@@ -716,10 +710,8 @@ static const struct omapdss_dpi_ops dpi_ops = { ...@@ -716,10 +710,8 @@ static const struct omapdss_dpi_ops dpi_ops = {
.get_timings = dpi_get_timings, .get_timings = dpi_get_timings,
}; };
static void dpi_init_output_port(struct platform_device *pdev, static void dpi_init_output_port(struct dpi_data *dpi, struct device_node *port)
struct device_node *port)
{ {
struct dpi_data *dpi = port->data;
struct omap_dss_device *out = &dpi->output; struct omap_dss_device *out = &dpi->output;
int r; int r;
u32 port_num; u32 port_num;
...@@ -741,10 +733,10 @@ static void dpi_init_output_port(struct platform_device *pdev, ...@@ -741,10 +733,10 @@ static void dpi_init_output_port(struct platform_device *pdev,
break; break;
} }
out->dev = &pdev->dev; out->dev = &dpi->pdev->dev;
out->id = OMAP_DSS_OUTPUT_DPI; out->id = OMAP_DSS_OUTPUT_DPI;
out->output_type = OMAP_DISPLAY_TYPE_DPI; out->output_type = OMAP_DISPLAY_TYPE_DPI;
out->dispc_channel = dpi_get_channel(port_num); out->dispc_channel = dpi_get_channel(dpi, port_num);
out->port_num = port_num; out->port_num = port_num;
out->ops.dpi = &dpi_ops; out->ops.dpi = &dpi_ops;
out->owner = THIS_MODULE; out->owner = THIS_MODULE;
...@@ -760,7 +752,8 @@ static void dpi_uninit_output_port(struct device_node *port) ...@@ -760,7 +752,8 @@ static void dpi_uninit_output_port(struct device_node *port)
omapdss_unregister_output(out); omapdss_unregister_output(out);
} }
int dpi_init_port(struct platform_device *pdev, struct device_node *port) int dpi_init_port(struct platform_device *pdev, struct device_node *port,
enum dss_model dss_model)
{ {
struct dpi_data *dpi; struct dpi_data *dpi;
struct device_node *ep; struct device_node *ep;
...@@ -786,11 +779,12 @@ int dpi_init_port(struct platform_device *pdev, struct device_node *port) ...@@ -786,11 +779,12 @@ int dpi_init_port(struct platform_device *pdev, struct device_node *port)
of_node_put(ep); of_node_put(ep);
dpi->pdev = pdev; dpi->pdev = pdev;
dpi->dss_model = dss_model;
port->data = dpi; port->data = dpi;
mutex_init(&dpi->lock); mutex_init(&dpi->lock);
dpi_init_output_port(pdev, port); dpi_init_output_port(dpi, port);
dpi->port_initialized = true; dpi->port_initialized = true;
......
...@@ -20,6 +20,8 @@ ...@@ -20,6 +20,8 @@
#define DSS_SUBSYS_NAME "DSI" #define DSS_SUBSYS_NAME "DSI"
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/device.h> #include <linux/device.h>
...@@ -42,12 +44,12 @@ ...@@ -42,12 +44,12 @@
#include <linux/of_graph.h> #include <linux/of_graph.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/component.h> #include <linux/component.h>
#include <linux/sys_soc.h>
#include <video/mipi_display.h> #include <video/mipi_display.h>
#include "omapdss.h" #include "omapdss.h"
#include "dss.h" #include "dss.h"
#include "dss_features.h"
#define DSI_CATCH_MISSING_TE #define DSI_CATCH_MISSING_TE
...@@ -228,6 +230,12 @@ static int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel); ...@@ -228,6 +230,12 @@ static int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel);
#define DSI_MAX_NR_ISRS 2 #define DSI_MAX_NR_ISRS 2
#define DSI_MAX_NR_LANES 5 #define DSI_MAX_NR_LANES 5
enum dsi_model {
DSI_MODEL_OMAP3,
DSI_MODEL_OMAP4,
DSI_MODEL_OMAP5,
};
enum dsi_lane_function { enum dsi_lane_function {
DSI_LANE_UNUSED = 0, DSI_LANE_UNUSED = 0,
DSI_LANE_CLK, DSI_LANE_CLK,
...@@ -299,12 +307,36 @@ struct dsi_lp_clock_info { ...@@ -299,12 +307,36 @@ struct dsi_lp_clock_info {
u16 lp_clk_div; u16 lp_clk_div;
}; };
struct dsi_module_id_data {
u32 address;
int id;
};
enum dsi_quirks {
DSI_QUIRK_PLL_PWR_BUG = (1 << 0), /* DSI-PLL power command 0x3 is not working */
DSI_QUIRK_DCS_CMD_CONFIG_VC = (1 << 1),
DSI_QUIRK_VC_OCP_WIDTH = (1 << 2),
DSI_QUIRK_REVERSE_TXCLKESC = (1 << 3),
DSI_QUIRK_GNQ = (1 << 4),
DSI_QUIRK_PHY_DCC = (1 << 5),
};
struct dsi_of_data {
enum dsi_model model;
const struct dss_pll_hw *pll_hw;
const struct dsi_module_id_data *modules;
unsigned int max_fck_freq;
unsigned int max_pll_lpdiv;
enum dsi_quirks quirks;
};
struct dsi_data { struct dsi_data {
struct platform_device *pdev; struct platform_device *pdev;
void __iomem *proto_base; void __iomem *proto_base;
void __iomem *phy_base; void __iomem *phy_base;
void __iomem *pll_base; void __iomem *pll_base;
const struct dsi_of_data *data;
int module_id; int module_id;
int irq; int irq;
...@@ -312,6 +344,7 @@ struct dsi_data { ...@@ -312,6 +344,7 @@ struct dsi_data {
bool is_enabled; bool is_enabled;
struct clk *dss_clk; struct clk *dss_clk;
struct regmap *syscon;
struct dispc_clock_info user_dispc_cinfo; struct dispc_clock_info user_dispc_cinfo;
struct dss_pll_clock_info user_dsi_cinfo; struct dss_pll_clock_info user_dsi_cinfo;
...@@ -397,13 +430,6 @@ struct dsi_packet_sent_handler_data { ...@@ -397,13 +430,6 @@ struct dsi_packet_sent_handler_data {
struct completion *completion; struct completion *completion;
}; };
struct dsi_module_id_data {
u32 address;
int id;
};
static const struct of_device_id dsi_of_match[];
#ifdef DSI_PERF_MEASURE #ifdef DSI_PERF_MEASURE
static bool dsi_perf; static bool dsi_perf;
module_param(dsi_perf, bool, 0644); module_param(dsi_perf, bool, 0644);
...@@ -1186,6 +1212,7 @@ static int dsi_regulator_init(struct platform_device *dsidev) ...@@ -1186,6 +1212,7 @@ static int dsi_regulator_init(struct platform_device *dsidev)
static void _dsi_print_reset_status(struct platform_device *dsidev) static void _dsi_print_reset_status(struct platform_device *dsidev)
{ {
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
u32 l; u32 l;
int b0, b1, b2; int b0, b1, b2;
...@@ -1194,7 +1221,7 @@ static void _dsi_print_reset_status(struct platform_device *dsidev) ...@@ -1194,7 +1221,7 @@ static void _dsi_print_reset_status(struct platform_device *dsidev)
* I/O. */ * I/O. */
l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5); l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5);
if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC)) { if (dsi->data->quirks & DSI_QUIRK_REVERSE_TXCLKESC) {
b0 = 28; b0 = 28;
b1 = 27; b1 = 27;
b2 = 26; b2 = 26;
...@@ -1297,7 +1324,7 @@ static int dsi_set_lp_clk_divisor(struct platform_device *dsidev) ...@@ -1297,7 +1324,7 @@ static int dsi_set_lp_clk_divisor(struct platform_device *dsidev)
unsigned long dsi_fclk; unsigned long dsi_fclk;
unsigned lp_clk_div; unsigned lp_clk_div;
unsigned long lp_clk; unsigned long lp_clk;
unsigned lpdiv_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_LPDIV); unsigned lpdiv_max = dsi->data->max_pll_lpdiv;
lp_clk_div = dsi->user_lp_cinfo.lp_clk_div; lp_clk_div = dsi->user_lp_cinfo.lp_clk_div;
...@@ -1349,11 +1376,12 @@ enum dsi_pll_power_state { ...@@ -1349,11 +1376,12 @@ enum dsi_pll_power_state {
static int dsi_pll_power(struct platform_device *dsidev, static int dsi_pll_power(struct platform_device *dsidev,
enum dsi_pll_power_state state) enum dsi_pll_power_state state)
{ {
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
int t = 0; int t = 0;
/* DSI-PLL power command 0x3 is not working */ /* DSI-PLL power command 0x3 is not working */
if (dss_has_feature(FEAT_DSI_PLL_PWR_BUG) && if ((dsi->data->quirks & DSI_QUIRK_PLL_PWR_BUG) &&
state == DSI_PLL_POWER_ON_DIV) state == DSI_PLL_POWER_ON_DIV)
state = DSI_PLL_POWER_ON_ALL; state = DSI_PLL_POWER_ON_ALL;
/* PLL_PWR_CMD */ /* PLL_PWR_CMD */
...@@ -1373,11 +1401,12 @@ static int dsi_pll_power(struct platform_device *dsidev, ...@@ -1373,11 +1401,12 @@ static int dsi_pll_power(struct platform_device *dsidev,
} }
static void dsi_pll_calc_dsi_fck(struct dss_pll_clock_info *cinfo) static void dsi_pll_calc_dsi_fck(struct dsi_data *dsi,
struct dss_pll_clock_info *cinfo)
{ {
unsigned long max_dsi_fck; unsigned long max_dsi_fck;
max_dsi_fck = dss_feat_get_param_max(FEAT_PARAM_DSI_FCK); max_dsi_fck = dsi->data->max_fck_freq;
cinfo->mX[HSDIV_DSI] = DIV_ROUND_UP(cinfo->clkdco, max_dsi_fck); cinfo->mX[HSDIV_DSI] = DIV_ROUND_UP(cinfo->clkdco, max_dsi_fck);
cinfo->clkout[HSDIV_DSI] = cinfo->clkdco / cinfo->mX[HSDIV_DSI]; cinfo->clkout[HSDIV_DSI] = cinfo->clkdco / cinfo->mX[HSDIV_DSI];
...@@ -1773,13 +1802,14 @@ static int dsi_cio_power(struct platform_device *dsidev, ...@@ -1773,13 +1802,14 @@ static int dsi_cio_power(struct platform_device *dsidev,
static unsigned dsi_get_line_buf_size(struct platform_device *dsidev) static unsigned dsi_get_line_buf_size(struct platform_device *dsidev)
{ {
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
int val; int val;
/* line buffer on OMAP3 is 1024 x 24bits */ /* line buffer on OMAP3 is 1024 x 24bits */
/* XXX: for some reason using full buffer size causes /* XXX: for some reason using full buffer size causes
* considerable TX slowdown with update sizes that fill the * considerable TX slowdown with update sizes that fill the
* whole buffer */ * whole buffer */
if (!dss_has_feature(FEAT_DSI_GNQ)) if (!(dsi->data->quirks & DSI_QUIRK_GNQ))
return 1023 * 3; return 1023 * 3;
val = REG_GET(dsidev, DSI_GNQ, 14, 12); /* VP1_LINE_BUFFER_SIZE */ val = REG_GET(dsidev, DSI_GNQ, 14, 12); /* VP1_LINE_BUFFER_SIZE */
...@@ -1872,6 +1902,7 @@ static inline unsigned ddr2ns(struct platform_device *dsidev, unsigned ddr) ...@@ -1872,6 +1902,7 @@ static inline unsigned ddr2ns(struct platform_device *dsidev, unsigned ddr)
static void dsi_cio_timings(struct platform_device *dsidev) static void dsi_cio_timings(struct platform_device *dsidev)
{ {
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
u32 r; u32 r;
u32 ths_prepare, ths_prepare_ths_zero, ths_trail, ths_exit; u32 ths_prepare, ths_prepare_ths_zero, ths_trail, ths_exit;
u32 tlpx_half, tclk_trail, tclk_zero; u32 tlpx_half, tclk_trail, tclk_zero;
...@@ -1934,7 +1965,7 @@ static void dsi_cio_timings(struct platform_device *dsidev) ...@@ -1934,7 +1965,7 @@ static void dsi_cio_timings(struct platform_device *dsidev)
r = FLD_MOD(r, tclk_trail, 15, 8); r = FLD_MOD(r, tclk_trail, 15, 8);
r = FLD_MOD(r, tclk_zero, 7, 0); r = FLD_MOD(r, tclk_zero, 7, 0);
if (dss_has_feature(FEAT_DSI_PHY_DCC)) { if (dsi->data->quirks & DSI_QUIRK_PHY_DCC) {
r = FLD_MOD(r, 0, 21, 21); /* DCCEN = disable */ r = FLD_MOD(r, 0, 21, 21); /* DCCEN = disable */
r = FLD_MOD(r, 1, 22, 22); /* CLKINP_DIVBY2EN = enable */ r = FLD_MOD(r, 1, 22, 22); /* CLKINP_DIVBY2EN = enable */
r = FLD_MOD(r, 1, 23, 23); /* CLKINP_SEL = enable */ r = FLD_MOD(r, 1, 23, 23); /* CLKINP_SEL = enable */
...@@ -2006,7 +2037,7 @@ static int dsi_cio_wait_tx_clk_esc_reset(struct platform_device *dsidev) ...@@ -2006,7 +2037,7 @@ static int dsi_cio_wait_tx_clk_esc_reset(struct platform_device *dsidev)
static const u8 offsets_new[] = { 24, 25, 26, 27, 28 }; static const u8 offsets_new[] = { 24, 25, 26, 27, 28 };
const u8 *offsets; const u8 *offsets;
if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC)) if (dsi->data->quirks & DSI_QUIRK_REVERSE_TXCLKESC)
offsets = offsets_old; offsets = offsets_old;
else else
offsets = offsets_new; offsets = offsets_new;
...@@ -2060,6 +2091,83 @@ static unsigned dsi_get_lane_mask(struct platform_device *dsidev) ...@@ -2060,6 +2091,83 @@ static unsigned dsi_get_lane_mask(struct platform_device *dsidev)
return mask; return mask;
} }
/* OMAP4 CONTROL_DSIPHY */
#define OMAP4_DSIPHY_SYSCON_OFFSET 0x78
#define OMAP4_DSI2_LANEENABLE_SHIFT 29
#define OMAP4_DSI2_LANEENABLE_MASK (0x7 << 29)
#define OMAP4_DSI1_LANEENABLE_SHIFT 24
#define OMAP4_DSI1_LANEENABLE_MASK (0x1f << 24)
#define OMAP4_DSI1_PIPD_SHIFT 19
#define OMAP4_DSI1_PIPD_MASK (0x1f << 19)
#define OMAP4_DSI2_PIPD_SHIFT 14
#define OMAP4_DSI2_PIPD_MASK (0x1f << 14)
static int dsi_omap4_mux_pads(struct dsi_data *dsi, unsigned int lanes)
{
u32 enable_mask, enable_shift;
u32 pipd_mask, pipd_shift;
if (dsi->module_id == 0) {
enable_mask = OMAP4_DSI1_LANEENABLE_MASK;
enable_shift = OMAP4_DSI1_LANEENABLE_SHIFT;
pipd_mask = OMAP4_DSI1_PIPD_MASK;
pipd_shift = OMAP4_DSI1_PIPD_SHIFT;
} else if (dsi->module_id == 1) {
enable_mask = OMAP4_DSI2_LANEENABLE_MASK;
enable_shift = OMAP4_DSI2_LANEENABLE_SHIFT;
pipd_mask = OMAP4_DSI2_PIPD_MASK;
pipd_shift = OMAP4_DSI2_PIPD_SHIFT;
} else {
return -ENODEV;
}
return regmap_update_bits(dsi->syscon, OMAP4_DSIPHY_SYSCON_OFFSET,
enable_mask | pipd_mask,
(lanes << enable_shift) | (lanes << pipd_shift));
}
/* OMAP5 CONTROL_DSIPHY */
#define OMAP5_DSIPHY_SYSCON_OFFSET 0x74
#define OMAP5_DSI1_LANEENABLE_SHIFT 24
#define OMAP5_DSI2_LANEENABLE_SHIFT 19
#define OMAP5_DSI_LANEENABLE_MASK 0x1f
static int dsi_omap5_mux_pads(struct dsi_data *dsi, unsigned int lanes)
{
u32 enable_shift;
if (dsi->module_id == 0)
enable_shift = OMAP5_DSI1_LANEENABLE_SHIFT;
else if (dsi->module_id == 1)
enable_shift = OMAP5_DSI2_LANEENABLE_SHIFT;
else
return -ENODEV;
return regmap_update_bits(dsi->syscon, OMAP5_DSIPHY_SYSCON_OFFSET,
OMAP5_DSI_LANEENABLE_MASK << enable_shift,
lanes << enable_shift);
}
static int dsi_enable_pads(struct dsi_data *dsi, unsigned int lane_mask)
{
if (dsi->data->model == DSI_MODEL_OMAP4)
return dsi_omap4_mux_pads(dsi, lane_mask);
if (dsi->data->model == DSI_MODEL_OMAP5)
return dsi_omap5_mux_pads(dsi, lane_mask);
return 0;
}
static void dsi_disable_pads(struct dsi_data *dsi)
{
if (dsi->data->model == DSI_MODEL_OMAP4)
dsi_omap4_mux_pads(dsi, 0);
else if (dsi->data->model == DSI_MODEL_OMAP5)
dsi_omap5_mux_pads(dsi, 0);
}
static int dsi_cio_init(struct platform_device *dsidev) static int dsi_cio_init(struct platform_device *dsidev)
{ {
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
...@@ -2068,7 +2176,7 @@ static int dsi_cio_init(struct platform_device *dsidev) ...@@ -2068,7 +2176,7 @@ static int dsi_cio_init(struct platform_device *dsidev)
DSSDBG("DSI CIO init starts"); DSSDBG("DSI CIO init starts");
r = dss_dsi_enable_pads(dsi->module_id, dsi_get_lane_mask(dsidev)); r = dsi_enable_pads(dsi, dsi_get_lane_mask(dsidev));
if (r) if (r)
return r; return r;
...@@ -2178,7 +2286,7 @@ static int dsi_cio_init(struct platform_device *dsidev) ...@@ -2178,7 +2286,7 @@ static int dsi_cio_init(struct platform_device *dsidev)
dsi_cio_disable_lane_override(dsidev); dsi_cio_disable_lane_override(dsidev);
err_scp_clk_dom: err_scp_clk_dom:
dsi_disable_scp_clk(dsidev); dsi_disable_scp_clk(dsidev);
dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dsidev)); dsi_disable_pads(dsi);
return r; return r;
} }
...@@ -2191,7 +2299,7 @@ static void dsi_cio_uninit(struct platform_device *dsidev) ...@@ -2191,7 +2299,7 @@ static void dsi_cio_uninit(struct platform_device *dsidev)
dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF); dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF);
dsi_disable_scp_clk(dsidev); dsi_disable_scp_clk(dsidev);
dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dsidev)); dsi_disable_pads(dsi);
} }
static void dsi_config_tx_fifo(struct platform_device *dsidev, static void dsi_config_tx_fifo(struct platform_device *dsidev,
...@@ -2439,7 +2547,7 @@ static void dsi_vc_initial_config(struct platform_device *dsidev, int channel) ...@@ -2439,7 +2547,7 @@ static void dsi_vc_initial_config(struct platform_device *dsidev, int channel)
r = FLD_MOD(r, 1, 7, 7); /* CS_TX_EN */ r = FLD_MOD(r, 1, 7, 7); /* CS_TX_EN */
r = FLD_MOD(r, 1, 8, 8); /* ECC_TX_EN */ r = FLD_MOD(r, 1, 8, 8); /* ECC_TX_EN */
r = FLD_MOD(r, 0, 9, 9); /* MODE_SPEED, high speed on/off */ r = FLD_MOD(r, 0, 9, 9); /* MODE_SPEED, high speed on/off */
if (dss_has_feature(FEAT_DSI_VC_OCP_WIDTH)) if (dsi->data->quirks & DSI_QUIRK_VC_OCP_WIDTH)
r = FLD_MOD(r, 3, 11, 10); /* OCP_WIDTH = 32 bit */ r = FLD_MOD(r, 3, 11, 10); /* OCP_WIDTH = 32 bit */
r = FLD_MOD(r, 4, 29, 27); /* DMA_RX_REQ_NB = no dma */ r = FLD_MOD(r, 4, 29, 27); /* DMA_RX_REQ_NB = no dma */
...@@ -2474,7 +2582,7 @@ static int dsi_vc_config_source(struct platform_device *dsidev, int channel, ...@@ -2474,7 +2582,7 @@ static int dsi_vc_config_source(struct platform_device *dsidev, int channel,
REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), source, 1, 1); REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), source, 1, 1);
/* DCS_CMD_ENABLE */ /* DCS_CMD_ENABLE */
if (dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC)) { if (dsi->data->quirks & DSI_QUIRK_DCS_CMD_CONFIG_VC) {
bool enable = source == DSI_VC_SOURCE_VP; bool enable = source == DSI_VC_SOURCE_VP;
REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), enable, 30, 30); REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), enable, 30, 30);
} }
...@@ -3607,7 +3715,7 @@ static int dsi_proto_config(struct platform_device *dsidev) ...@@ -3607,7 +3715,7 @@ static int dsi_proto_config(struct platform_device *dsidev)
r = FLD_MOD(r, 0, 8, 8); /* VP_CLK_POL */ r = FLD_MOD(r, 0, 8, 8); /* VP_CLK_POL */
r = FLD_MOD(r, 1, 14, 14); /* TRIGGER_RESET_MODE */ r = FLD_MOD(r, 1, 14, 14); /* TRIGGER_RESET_MODE */
r = FLD_MOD(r, 1, 19, 19); /* EOT_ENABLE */ r = FLD_MOD(r, 1, 19, 19); /* EOT_ENABLE */
if (!dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC)) { if (!(dsi->data->quirks & DSI_QUIRK_DCS_CMD_CONFIG_VC)) {
r = FLD_MOD(r, 1, 24, 24); /* DCS_CMD_ENABLE */ r = FLD_MOD(r, 1, 24, 24); /* DCS_CMD_ENABLE */
/* DCS_CMD_CODE, 1=start, 0=continue */ /* DCS_CMD_CODE, 1=start, 0=continue */
r = FLD_MOD(r, 0, 25, 25); r = FLD_MOD(r, 0, 25, 25);
...@@ -4450,6 +4558,7 @@ static bool dsi_cm_calc_pll_cb(int n, int m, unsigned long fint, ...@@ -4450,6 +4558,7 @@ static bool dsi_cm_calc_pll_cb(int n, int m, unsigned long fint,
unsigned long clkdco, void *data) unsigned long clkdco, void *data)
{ {
struct dsi_clk_calc_ctx *ctx = data; struct dsi_clk_calc_ctx *ctx = data;
struct dsi_data *dsi = dsi_get_dsidrv_data(ctx->dsidev);
ctx->dsi_cinfo.n = n; ctx->dsi_cinfo.n = n;
ctx->dsi_cinfo.m = m; ctx->dsi_cinfo.m = m;
...@@ -4457,7 +4566,7 @@ static bool dsi_cm_calc_pll_cb(int n, int m, unsigned long fint, ...@@ -4457,7 +4566,7 @@ static bool dsi_cm_calc_pll_cb(int n, int m, unsigned long fint,
ctx->dsi_cinfo.clkdco = clkdco; ctx->dsi_cinfo.clkdco = clkdco;
return dss_pll_hsdiv_calc_a(ctx->pll, clkdco, ctx->req_pck_min, return dss_pll_hsdiv_calc_a(ctx->pll, clkdco, ctx->req_pck_min,
dss_feat_get_param_max(FEAT_PARAM_DSS_FCK), dsi->data->max_fck_freq,
dsi_cm_calc_hsdiv_cb, ctx); dsi_cm_calc_hsdiv_cb, ctx);
} }
...@@ -4749,6 +4858,7 @@ static bool dsi_vm_calc_pll_cb(int n, int m, unsigned long fint, ...@@ -4749,6 +4858,7 @@ static bool dsi_vm_calc_pll_cb(int n, int m, unsigned long fint,
unsigned long clkdco, void *data) unsigned long clkdco, void *data)
{ {
struct dsi_clk_calc_ctx *ctx = data; struct dsi_clk_calc_ctx *ctx = data;
struct dsi_data *dsi = dsi_get_dsidrv_data(ctx->dsidev);
ctx->dsi_cinfo.n = n; ctx->dsi_cinfo.n = n;
ctx->dsi_cinfo.m = m; ctx->dsi_cinfo.m = m;
...@@ -4756,7 +4866,7 @@ static bool dsi_vm_calc_pll_cb(int n, int m, unsigned long fint, ...@@ -4756,7 +4866,7 @@ static bool dsi_vm_calc_pll_cb(int n, int m, unsigned long fint,
ctx->dsi_cinfo.clkdco = clkdco; ctx->dsi_cinfo.clkdco = clkdco;
return dss_pll_hsdiv_calc_a(ctx->pll, clkdco, ctx->req_pck_min, return dss_pll_hsdiv_calc_a(ctx->pll, clkdco, ctx->req_pck_min,
dss_feat_get_param_max(FEAT_PARAM_DSS_FCK), dsi->data->max_fck_freq,
dsi_vm_calc_hsdiv_cb, ctx); dsi_vm_calc_hsdiv_cb, ctx);
} }
...@@ -4827,7 +4937,7 @@ static int dsi_set_config(struct omap_dss_device *dssdev, ...@@ -4827,7 +4937,7 @@ static int dsi_set_config(struct omap_dss_device *dssdev,
goto err; goto err;
} }
dsi_pll_calc_dsi_fck(&ctx.dsi_cinfo); dsi_pll_calc_dsi_fck(dsi, &ctx.dsi_cinfo);
r = dsi_lp_clock_calc(ctx.dsi_cinfo.clkout[HSDIV_DSI], r = dsi_lp_clock_calc(ctx.dsi_cinfo.clkout[HSDIV_DSI],
config->lp_clk_min, config->lp_clk_max, &dsi->user_lp_cinfo); config->lp_clk_min, config->lp_clk_max, &dsi->user_lp_cinfo);
...@@ -4857,24 +4967,14 @@ static int dsi_set_config(struct omap_dss_device *dssdev, ...@@ -4857,24 +4967,14 @@ static int dsi_set_config(struct omap_dss_device *dssdev,
* the channel in some more dynamic manner, or get the channel as a user * the channel in some more dynamic manner, or get the channel as a user
* parameter. * parameter.
*/ */
static enum omap_channel dsi_get_channel(int module_id) static enum omap_channel dsi_get_channel(struct dsi_data *dsi)
{ {
switch (omapdss_get_version()) { switch (dsi->data->model) {
case OMAPDSS_VER_OMAP24xx: case DSI_MODEL_OMAP3:
case OMAPDSS_VER_AM43xx:
DSSWARN("DSI not supported\n");
return OMAP_DSS_CHANNEL_LCD; return OMAP_DSS_CHANNEL_LCD;
case OMAPDSS_VER_OMAP34xx_ES1: case DSI_MODEL_OMAP4:
case OMAPDSS_VER_OMAP34xx_ES3: switch (dsi->module_id) {
case OMAPDSS_VER_OMAP3630:
case OMAPDSS_VER_AM35xx:
return OMAP_DSS_CHANNEL_LCD;
case OMAPDSS_VER_OMAP4430_ES1:
case OMAPDSS_VER_OMAP4430_ES2:
case OMAPDSS_VER_OMAP4:
switch (module_id) {
case 0: case 0:
return OMAP_DSS_CHANNEL_LCD; return OMAP_DSS_CHANNEL_LCD;
case 1: case 1:
...@@ -4884,8 +4984,8 @@ static enum omap_channel dsi_get_channel(int module_id) ...@@ -4884,8 +4984,8 @@ static enum omap_channel dsi_get_channel(int module_id)
return OMAP_DSS_CHANNEL_LCD; return OMAP_DSS_CHANNEL_LCD;
} }
case OMAPDSS_VER_OMAP5: case DSI_MODEL_OMAP5:
switch (module_id) { switch (dsi->module_id) {
case 0: case 0:
return OMAP_DSS_CHANNEL_LCD; return OMAP_DSS_CHANNEL_LCD;
case 1: case 1:
...@@ -5065,7 +5165,7 @@ static void dsi_init_output(struct platform_device *dsidev) ...@@ -5065,7 +5165,7 @@ static void dsi_init_output(struct platform_device *dsidev)
out->output_type = OMAP_DISPLAY_TYPE_DSI; out->output_type = OMAP_DISPLAY_TYPE_DSI;
out->name = dsi->module_id == 0 ? "dsi.0" : "dsi.1"; out->name = dsi->module_id == 0 ? "dsi.0" : "dsi.1";
out->dispc_channel = dsi_get_channel(dsi->module_id); out->dispc_channel = dsi_get_channel(dsi);
out->ops.dsi = &dsi_ops; out->ops.dsi = &dsi_ops;
out->owner = THIS_MODULE; out->owner = THIS_MODULE;
...@@ -5240,29 +5340,7 @@ static int dsi_init_pll_data(struct platform_device *dsidev) ...@@ -5240,29 +5340,7 @@ static int dsi_init_pll_data(struct platform_device *dsidev)
pll->id = dsi->module_id == 0 ? DSS_PLL_DSI1 : DSS_PLL_DSI2; pll->id = dsi->module_id == 0 ? DSS_PLL_DSI1 : DSS_PLL_DSI2;
pll->clkin = clk; pll->clkin = clk;
pll->base = dsi->pll_base; pll->base = dsi->pll_base;
pll->hw = dsi->data->pll_hw;
switch (omapdss_get_version()) {
case OMAPDSS_VER_OMAP34xx_ES1:
case OMAPDSS_VER_OMAP34xx_ES3:
case OMAPDSS_VER_OMAP3630:
case OMAPDSS_VER_AM35xx:
pll->hw = &dss_omap3_dsi_pll_hw;
break;
case OMAPDSS_VER_OMAP4430_ES1:
case OMAPDSS_VER_OMAP4430_ES2:
case OMAPDSS_VER_OMAP4:
pll->hw = &dss_omap4_dsi_pll_hw;
break;
case OMAPDSS_VER_OMAP5:
pll->hw = &dss_omap5_dsi_pll_hw;
break;
default:
return -ENODEV;
}
pll->ops = &dsi_pll_ops; pll->ops = &dsi_pll_ops;
r = dss_pll_register(pll); r = dss_pll_register(pll);
...@@ -5273,9 +5351,74 @@ static int dsi_init_pll_data(struct platform_device *dsidev) ...@@ -5273,9 +5351,74 @@ static int dsi_init_pll_data(struct platform_device *dsidev)
} }
/* DSI1 HW IP initialisation */ /* DSI1 HW IP initialisation */
static const struct dsi_of_data dsi_of_data_omap34xx = {
.model = DSI_MODEL_OMAP3,
.pll_hw = &dss_omap3_dsi_pll_hw,
.modules = (const struct dsi_module_id_data[]) {
{ .address = 0x4804fc00, .id = 0, },
{ },
},
.max_fck_freq = 173000000,
.max_pll_lpdiv = (1 << 13) - 1,
.quirks = DSI_QUIRK_REVERSE_TXCLKESC,
};
static const struct dsi_of_data dsi_of_data_omap36xx = {
.model = DSI_MODEL_OMAP3,
.pll_hw = &dss_omap3_dsi_pll_hw,
.modules = (const struct dsi_module_id_data[]) {
{ .address = 0x4804fc00, .id = 0, },
{ },
},
.max_fck_freq = 173000000,
.max_pll_lpdiv = (1 << 13) - 1,
.quirks = DSI_QUIRK_PLL_PWR_BUG,
};
static const struct dsi_of_data dsi_of_data_omap4 = {
.model = DSI_MODEL_OMAP4,
.pll_hw = &dss_omap4_dsi_pll_hw,
.modules = (const struct dsi_module_id_data[]) {
{ .address = 0x58004000, .id = 0, },
{ .address = 0x58005000, .id = 1, },
{ },
},
.max_fck_freq = 170000000,
.max_pll_lpdiv = (1 << 13) - 1,
.quirks = DSI_QUIRK_DCS_CMD_CONFIG_VC | DSI_QUIRK_VC_OCP_WIDTH
| DSI_QUIRK_GNQ,
};
static const struct dsi_of_data dsi_of_data_omap5 = {
.model = DSI_MODEL_OMAP5,
.pll_hw = &dss_omap5_dsi_pll_hw,
.modules = (const struct dsi_module_id_data[]) {
{ .address = 0x58004000, .id = 0, },
{ .address = 0x58009000, .id = 1, },
{ },
},
.max_fck_freq = 209250000,
.max_pll_lpdiv = (1 << 13) - 1,
.quirks = DSI_QUIRK_DCS_CMD_CONFIG_VC | DSI_QUIRK_VC_OCP_WIDTH
| DSI_QUIRK_GNQ | DSI_QUIRK_PHY_DCC,
};
static const struct of_device_id dsi_of_match[] = {
{ .compatible = "ti,omap3-dsi", .data = &dsi_of_data_omap36xx, },
{ .compatible = "ti,omap4-dsi", .data = &dsi_of_data_omap4, },
{ .compatible = "ti,omap5-dsi", .data = &dsi_of_data_omap5, },
{},
};
static const struct soc_device_attribute dsi_soc_devices[] = {
{ .machine = "OMAP3[45]*", .data = &dsi_of_data_omap34xx },
{ .machine = "AM35*", .data = &dsi_of_data_omap34xx },
{ /* sentinel */ }
};
static int dsi_bind(struct device *dev, struct device *master, void *data) static int dsi_bind(struct device *dev, struct device *master, void *data)
{ {
struct platform_device *dsidev = to_platform_device(dev); struct platform_device *dsidev = to_platform_device(dev);
const struct soc_device_attribute *soc;
const struct dsi_module_id_data *d; const struct dsi_module_id_data *d;
u32 rev; u32 rev;
int r, i; int r, i;
...@@ -5339,7 +5482,13 @@ static int dsi_bind(struct device *dev, struct device *master, void *data) ...@@ -5339,7 +5482,13 @@ static int dsi_bind(struct device *dev, struct device *master, void *data)
return r; return r;
} }
d = of_match_node(dsi_of_match, dsidev->dev.of_node)->data; soc = soc_device_match(dsi_soc_devices);
if (soc)
dsi->data = soc->data;
else
dsi->data = of_match_node(dsi_of_match, dev->of_node)->data;
d = dsi->data->modules;
while (d->address != 0 && d->address != dsi_mem->start) while (d->address != 0 && d->address != dsi_mem->start)
d++; d++;
...@@ -5350,6 +5499,24 @@ static int dsi_bind(struct device *dev, struct device *master, void *data) ...@@ -5350,6 +5499,24 @@ static int dsi_bind(struct device *dev, struct device *master, void *data)
dsi->module_id = d->id; dsi->module_id = d->id;
if (dsi->data->model == DSI_MODEL_OMAP4 ||
dsi->data->model == DSI_MODEL_OMAP5) {
struct device_node *np;
/*
* The OMAP4/5 display DT bindings don't reference the padconf
* syscon. Our only option to retrieve it is to find it by name.
*/
np = of_find_node_by_name(NULL,
dsi->data->model == DSI_MODEL_OMAP4 ?
"omap4_padconf_global" : "omap5_padconf_global");
if (!np)
return -ENODEV;
dsi->syscon = syscon_node_to_regmap(np);
of_node_put(np);
}
/* DSI VCs initialization */ /* DSI VCs initialization */
for (i = 0; i < ARRAY_SIZE(dsi->vc); i++) { for (i = 0; i < ARRAY_SIZE(dsi->vc); i++) {
dsi->vc[i].source = DSI_VC_SOURCE_L4; dsi->vc[i].source = DSI_VC_SOURCE_L4;
...@@ -5375,7 +5542,7 @@ static int dsi_bind(struct device *dev, struct device *master, void *data) ...@@ -5375,7 +5542,7 @@ static int dsi_bind(struct device *dev, struct device *master, void *data)
/* DSI on OMAP3 doesn't have register DSI_GNQ, set number /* DSI on OMAP3 doesn't have register DSI_GNQ, set number
* of data to 3 by default */ * of data to 3 by default */
if (dss_has_feature(FEAT_DSI_GNQ)) if (dsi->data->quirks & DSI_QUIRK_GNQ)
/* NB_DATA_LANES */ /* NB_DATA_LANES */
dsi->num_lanes_supported = 1 + REG_GET(dsidev, DSI_GNQ, 11, 9); dsi->num_lanes_supported = 1 + REG_GET(dsidev, DSI_GNQ, 11, 9);
else else
...@@ -5495,30 +5662,6 @@ static const struct dev_pm_ops dsi_pm_ops = { ...@@ -5495,30 +5662,6 @@ static const struct dev_pm_ops dsi_pm_ops = {
.runtime_resume = dsi_runtime_resume, .runtime_resume = dsi_runtime_resume,
}; };
static const struct dsi_module_id_data dsi_of_data_omap3[] = {
{ .address = 0x4804fc00, .id = 0, },
{ },
};
static const struct dsi_module_id_data dsi_of_data_omap4[] = {
{ .address = 0x58004000, .id = 0, },
{ .address = 0x58005000, .id = 1, },
{ },
};
static const struct dsi_module_id_data dsi_of_data_omap5[] = {
{ .address = 0x58004000, .id = 0, },
{ .address = 0x58009000, .id = 1, },
{ },
};
static const struct of_device_id dsi_of_match[] = {
{ .compatible = "ti,omap3-dsi", .data = dsi_of_data_omap3, },
{ .compatible = "ti,omap4-dsi", .data = dsi_of_data_omap4, },
{ .compatible = "ti,omap5-dsi", .data = dsi_of_data_omap5, },
{},
};
static struct platform_driver omap_dsihw_driver = { static struct platform_driver omap_dsihw_driver = {
.probe = dsi_probe, .probe = dsi_probe,
.remove = dsi_remove, .remove = dsi_remove,
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#define DSS_SUBSYS_NAME "DSS" #define DSS_SUBSYS_NAME "DSS"
#include <linux/debugfs.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/io.h> #include <linux/io.h>
...@@ -38,14 +39,15 @@ ...@@ -38,14 +39,15 @@
#include <linux/mfd/syscon.h> #include <linux/mfd/syscon.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_graph.h> #include <linux/of_graph.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/suspend.h> #include <linux/suspend.h>
#include <linux/component.h> #include <linux/component.h>
#include <linux/sys_soc.h>
#include "omapdss.h" #include "omapdss.h"
#include "dss.h" #include "dss.h"
#include "dss_features.h"
#define DSS_SZ_REGS SZ_512 #define DSS_SZ_REGS SZ_512
...@@ -69,15 +71,24 @@ struct dss_reg { ...@@ -69,15 +71,24 @@ struct dss_reg {
#define REG_FLD_MOD(idx, val, start, end) \ #define REG_FLD_MOD(idx, val, start, end) \
dss_write_reg(idx, FLD_MOD(dss_read_reg(idx), val, start, end)) dss_write_reg(idx, FLD_MOD(dss_read_reg(idx), val, start, end))
struct dss_ops {
int (*dpi_select_source)(int port, enum omap_channel channel);
int (*select_lcd_source)(enum omap_channel channel,
enum dss_clk_source clk_src);
};
struct dss_features { struct dss_features {
enum dss_model model;
u8 fck_div_max; u8 fck_div_max;
unsigned int fck_freq_max;
u8 dss_fck_multiplier; u8 dss_fck_multiplier;
const char *parent_clk_name; const char *parent_clk_name;
const enum omap_display_type *ports; const enum omap_display_type *ports;
int num_ports; int num_ports;
int (*dpi_select_source)(int port, enum omap_channel channel); const enum omap_dss_output_id *outputs;
int (*select_lcd_source)(enum omap_channel channel, const struct dss_ops *ops;
enum dss_clk_source clk_src); struct dss_reg_field dispc_clk_switch;
bool has_lcd_clk_src;
}; };
static struct { static struct {
...@@ -139,8 +150,7 @@ static void dss_save_context(void) ...@@ -139,8 +150,7 @@ static void dss_save_context(void)
SR(CONTROL); SR(CONTROL);
if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) & if (dss.feat->outputs[OMAP_DSS_CHANNEL_LCD] & OMAP_DSS_OUTPUT_SDI) {
OMAP_DISPLAY_TYPE_SDI) {
SR(SDI_CONTROL); SR(SDI_CONTROL);
SR(PLL_CONTROL); SR(PLL_CONTROL);
} }
...@@ -159,8 +169,7 @@ static void dss_restore_context(void) ...@@ -159,8 +169,7 @@ static void dss_restore_context(void)
RR(CONTROL); RR(CONTROL);
if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) & if (dss.feat->outputs[OMAP_DSS_CHANNEL_LCD] & OMAP_DSS_OUTPUT_SDI) {
OMAP_DISPLAY_TYPE_SDI) {
RR(SDI_CONTROL); RR(SDI_CONTROL);
RR(PLL_CONTROL); RR(PLL_CONTROL);
} }
...@@ -390,8 +399,7 @@ static void dss_dump_regs(struct seq_file *s) ...@@ -390,8 +399,7 @@ static void dss_dump_regs(struct seq_file *s)
DUMPREG(DSS_SYSSTATUS); DUMPREG(DSS_SYSSTATUS);
DUMPREG(DSS_CONTROL); DUMPREG(DSS_CONTROL);
if (dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_LCD) & if (dss.feat->outputs[OMAP_DSS_CHANNEL_LCD] & OMAP_DSS_OUTPUT_SDI) {
OMAP_DISPLAY_TYPE_SDI) {
DUMPREG(DSS_SDI_CONTROL); DUMPREG(DSS_SDI_CONTROL);
DUMPREG(DSS_PLL_CONTROL); DUMPREG(DSS_PLL_CONTROL);
DUMPREG(DSS_SDI_STATUS); DUMPREG(DSS_SDI_STATUS);
...@@ -419,14 +427,12 @@ static int dss_get_channel_index(enum omap_channel channel) ...@@ -419,14 +427,12 @@ static int dss_get_channel_index(enum omap_channel channel)
static void dss_select_dispc_clk_source(enum dss_clk_source clk_src) static void dss_select_dispc_clk_source(enum dss_clk_source clk_src)
{ {
int b; int b;
u8 start, end;
/* /*
* We always use PRCM clock as the DISPC func clock, except on DSS3, * We always use PRCM clock as the DISPC func clock, except on DSS3,
* where we don't have separate DISPC and LCD clock sources. * where we don't have separate DISPC and LCD clock sources.
*/ */
if (WARN_ON(dss_has_feature(FEAT_LCD_CLK_SRC) && if (WARN_ON(dss.feat->has_lcd_clk_src && clk_src != DSS_CLK_SRC_FCK))
clk_src != DSS_CLK_SRC_FCK))
return; return;
switch (clk_src) { switch (clk_src) {
...@@ -444,9 +450,9 @@ static void dss_select_dispc_clk_source(enum dss_clk_source clk_src) ...@@ -444,9 +450,9 @@ static void dss_select_dispc_clk_source(enum dss_clk_source clk_src)
return; return;
} }
dss_feat_get_reg_field(FEAT_REG_DISPC_CLK_SWITCH, &start, &end); REG_FLD_MOD(DSS_CONTROL, b, /* DISPC_CLK_SWITCH */
dss.feat->dispc_clk_switch.start,
REG_FLD_MOD(DSS_CONTROL, b, start, end); /* DISPC_CLK_SWITCH */ dss.feat->dispc_clk_switch.end);
dss.dispc_clk_source = clk_src; dss.dispc_clk_source = clk_src;
} }
...@@ -570,13 +576,13 @@ void dss_select_lcd_clk_source(enum omap_channel channel, ...@@ -570,13 +576,13 @@ void dss_select_lcd_clk_source(enum omap_channel channel,
int idx = dss_get_channel_index(channel); int idx = dss_get_channel_index(channel);
int r; int r;
if (!dss_has_feature(FEAT_LCD_CLK_SRC)) { if (!dss.feat->has_lcd_clk_src) {
dss_select_dispc_clk_source(clk_src); dss_select_dispc_clk_source(clk_src);
dss.lcd_clk_source[idx] = clk_src; dss.lcd_clk_source[idx] = clk_src;
return; return;
} }
r = dss.feat->select_lcd_source(channel, clk_src); r = dss.feat->ops->select_lcd_source(channel, clk_src);
if (r) if (r)
return; return;
...@@ -595,7 +601,7 @@ enum dss_clk_source dss_get_dsi_clk_source(int dsi_module) ...@@ -595,7 +601,7 @@ enum dss_clk_source dss_get_dsi_clk_source(int dsi_module)
enum dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel) enum dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel)
{ {
if (dss_has_feature(FEAT_LCD_CLK_SRC)) { if (dss.feat->has_lcd_clk_src) {
int idx = dss_get_channel_index(channel); int idx = dss_get_channel_index(channel);
return dss.lcd_clk_source[idx]; return dss.lcd_clk_source[idx];
} else { } else {
...@@ -615,7 +621,7 @@ bool dss_div_calc(unsigned long pck, unsigned long fck_min, ...@@ -615,7 +621,7 @@ bool dss_div_calc(unsigned long pck, unsigned long fck_min,
unsigned long prate; unsigned long prate;
unsigned m; unsigned m;
fck_hw_max = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); fck_hw_max = dss.feat->fck_freq_max;
if (dss.parent_clk == NULL) { if (dss.parent_clk == NULL) {
unsigned pckd; unsigned pckd;
...@@ -673,6 +679,16 @@ unsigned long dss_get_dispc_clk_rate(void) ...@@ -673,6 +679,16 @@ unsigned long dss_get_dispc_clk_rate(void)
return dss.dss_clk_rate; return dss.dss_clk_rate;
} }
unsigned long dss_get_max_fck_rate(void)
{
return dss.feat->fck_freq_max;
}
enum omap_dss_output_id dss_get_supported_outputs(enum omap_channel channel)
{
return dss.feat->outputs[channel];
}
static int dss_setup_default_clock(void) static int dss_setup_default_clock(void)
{ {
unsigned long max_dss_fck, prate; unsigned long max_dss_fck, prate;
...@@ -680,7 +696,7 @@ static int dss_setup_default_clock(void) ...@@ -680,7 +696,7 @@ static int dss_setup_default_clock(void)
unsigned fck_div; unsigned fck_div;
int r; int r;
max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); max_dss_fck = dss.feat->fck_freq_max;
if (dss.parent_clk == NULL) { if (dss.parent_clk == NULL) {
fck = clk_round_rate(dss.dss_clk, max_dss_fck); fck = clk_round_rate(dss.dss_clk, max_dss_fck);
...@@ -721,27 +737,29 @@ void dss_set_dac_pwrdn_bgz(bool enable) ...@@ -721,27 +737,29 @@ void dss_set_dac_pwrdn_bgz(bool enable)
void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select src) void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select src)
{ {
enum omap_display_type dp; enum omap_dss_output_id outputs;
dp = dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_DIGIT);
outputs = dss.feat->outputs[OMAP_DSS_CHANNEL_DIGIT];
/* Complain about invalid selections */ /* Complain about invalid selections */
WARN_ON((src == DSS_VENC_TV_CLK) && !(dp & OMAP_DISPLAY_TYPE_VENC)); WARN_ON((src == DSS_VENC_TV_CLK) && !(outputs & OMAP_DSS_OUTPUT_VENC));
WARN_ON((src == DSS_HDMI_M_PCLK) && !(dp & OMAP_DISPLAY_TYPE_HDMI)); WARN_ON((src == DSS_HDMI_M_PCLK) && !(outputs & OMAP_DSS_OUTPUT_HDMI));
/* Select only if we have options */ /* Select only if we have options */
if ((dp & OMAP_DISPLAY_TYPE_VENC) && (dp & OMAP_DISPLAY_TYPE_HDMI)) if ((outputs & OMAP_DSS_OUTPUT_VENC) &&
(outputs & OMAP_DSS_OUTPUT_HDMI))
REG_FLD_MOD(DSS_CONTROL, src, 15, 15); /* VENC_HDMI_SWITCH */ REG_FLD_MOD(DSS_CONTROL, src, 15, 15); /* VENC_HDMI_SWITCH */
} }
enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void) enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void)
{ {
enum omap_display_type displays; enum omap_dss_output_id outputs;
displays = dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_DIGIT); outputs = dss.feat->outputs[OMAP_DSS_CHANNEL_DIGIT];
if ((displays & OMAP_DISPLAY_TYPE_HDMI) == 0) if ((outputs & OMAP_DSS_OUTPUT_HDMI) == 0)
return DSS_VENC_TV_CLK; return DSS_VENC_TV_CLK;
if ((displays & OMAP_DISPLAY_TYPE_VENC) == 0) if ((outputs & OMAP_DSS_OUTPUT_VENC) == 0)
return DSS_HDMI_M_PCLK; return DSS_HDMI_M_PCLK;
return REG_GET(DSS_CONTROL, 15, 15); return REG_GET(DSS_CONTROL, 15, 15);
...@@ -823,7 +841,7 @@ static int dss_dpi_select_source_dra7xx(int port, enum omap_channel channel) ...@@ -823,7 +841,7 @@ static int dss_dpi_select_source_dra7xx(int port, enum omap_channel channel)
int dss_dpi_select_source(int port, enum omap_channel channel) int dss_dpi_select_source(int port, enum omap_channel channel)
{ {
return dss.feat->dpi_select_source(port, channel); return dss.feat->ops->dpi_select_source(port, channel);
} }
static int dss_get_clocks(void) static int dss_get_clocks(void)
...@@ -882,7 +900,7 @@ void dss_runtime_put(void) ...@@ -882,7 +900,7 @@ void dss_runtime_put(void)
/* DEBUGFS */ /* DEBUGFS */
#if defined(CONFIG_OMAP2_DSS_DEBUGFS) #if defined(CONFIG_OMAP2_DSS_DEBUGFS)
void dss_debug_dump_clocks(struct seq_file *s) static void dss_debug_dump_clocks(struct seq_file *s)
{ {
dss_dump_clocks(s); dss_dump_clocks(s);
dispc_dump_clocks(s); dispc_dump_clocks(s);
...@@ -890,8 +908,88 @@ void dss_debug_dump_clocks(struct seq_file *s) ...@@ -890,8 +908,88 @@ void dss_debug_dump_clocks(struct seq_file *s)
dsi_dump_clocks(s); dsi_dump_clocks(s);
#endif #endif
} }
#endif
static int dss_debug_show(struct seq_file *s, void *unused)
{
void (*func)(struct seq_file *) = s->private;
func(s);
return 0;
}
static int dss_debug_open(struct inode *inode, struct file *file)
{
return single_open(file, dss_debug_show, inode->i_private);
}
static const struct file_operations dss_debug_fops = {
.open = dss_debug_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static struct dentry *dss_debugfs_dir;
static int dss_initialize_debugfs(void)
{
dss_debugfs_dir = debugfs_create_dir("omapdss", NULL);
if (IS_ERR(dss_debugfs_dir)) {
int err = PTR_ERR(dss_debugfs_dir);
dss_debugfs_dir = NULL;
return err;
}
debugfs_create_file("clk", S_IRUGO, dss_debugfs_dir,
&dss_debug_dump_clocks, &dss_debug_fops);
return 0;
}
static void dss_uninitialize_debugfs(void)
{
if (dss_debugfs_dir)
debugfs_remove_recursive(dss_debugfs_dir);
}
int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *))
{
struct dentry *d;
d = debugfs_create_file(name, S_IRUGO, dss_debugfs_dir,
write, &dss_debug_fops);
return PTR_ERR_OR_ZERO(d);
}
#else /* CONFIG_OMAP2_DSS_DEBUGFS */
static inline int dss_initialize_debugfs(void)
{
return 0;
}
static inline void dss_uninitialize_debugfs(void)
{
}
#endif /* CONFIG_OMAP2_DSS_DEBUGFS */
static const struct dss_ops dss_ops_omap2_omap3 = {
.dpi_select_source = &dss_dpi_select_source_omap2_omap3,
};
static const struct dss_ops dss_ops_omap4 = {
.dpi_select_source = &dss_dpi_select_source_omap4,
.select_lcd_source = &dss_lcd_clk_mux_omap4,
};
static const struct dss_ops dss_ops_omap5 = {
.dpi_select_source = &dss_dpi_select_source_omap5,
.select_lcd_source = &dss_lcd_clk_mux_omap5,
};
static const struct dss_ops dss_ops_dra7 = {
.dpi_select_source = &dss_dpi_select_source_dra7xx,
.select_lcd_source = &dss_lcd_clk_mux_dra7,
};
static const enum omap_display_type omap2plus_ports[] = { static const enum omap_display_type omap2plus_ports[] = {
OMAP_DISPLAY_TYPE_DPI, OMAP_DISPLAY_TYPE_DPI,
...@@ -908,130 +1006,168 @@ static const enum omap_display_type dra7xx_ports[] = { ...@@ -908,130 +1006,168 @@ static const enum omap_display_type dra7xx_ports[] = {
OMAP_DISPLAY_TYPE_DPI, OMAP_DISPLAY_TYPE_DPI,
}; };
static const enum omap_dss_output_id omap2_dss_supported_outputs[] = {
/* OMAP_DSS_CHANNEL_LCD */
OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI,
/* OMAP_DSS_CHANNEL_DIGIT */
OMAP_DSS_OUTPUT_VENC,
};
static const enum omap_dss_output_id omap3430_dss_supported_outputs[] = {
/* OMAP_DSS_CHANNEL_LCD */
OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
OMAP_DSS_OUTPUT_SDI | OMAP_DSS_OUTPUT_DSI1,
/* OMAP_DSS_CHANNEL_DIGIT */
OMAP_DSS_OUTPUT_VENC,
};
static const enum omap_dss_output_id omap3630_dss_supported_outputs[] = {
/* OMAP_DSS_CHANNEL_LCD */
OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
OMAP_DSS_OUTPUT_DSI1,
/* OMAP_DSS_CHANNEL_DIGIT */
OMAP_DSS_OUTPUT_VENC,
};
static const enum omap_dss_output_id am43xx_dss_supported_outputs[] = {
/* OMAP_DSS_CHANNEL_LCD */
OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI,
};
static const enum omap_dss_output_id omap4_dss_supported_outputs[] = {
/* OMAP_DSS_CHANNEL_LCD */
OMAP_DSS_OUTPUT_DBI | OMAP_DSS_OUTPUT_DSI1,
/* OMAP_DSS_CHANNEL_DIGIT */
OMAP_DSS_OUTPUT_VENC | OMAP_DSS_OUTPUT_HDMI,
/* OMAP_DSS_CHANNEL_LCD2 */
OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
OMAP_DSS_OUTPUT_DSI2,
};
static const enum omap_dss_output_id omap5_dss_supported_outputs[] = {
/* OMAP_DSS_CHANNEL_LCD */
OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
OMAP_DSS_OUTPUT_DSI1 | OMAP_DSS_OUTPUT_DSI2,
/* OMAP_DSS_CHANNEL_DIGIT */
OMAP_DSS_OUTPUT_HDMI,
/* OMAP_DSS_CHANNEL_LCD2 */
OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
OMAP_DSS_OUTPUT_DSI1,
/* OMAP_DSS_CHANNEL_LCD3 */
OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
OMAP_DSS_OUTPUT_DSI2,
};
static const struct dss_features omap24xx_dss_feats = { static const struct dss_features omap24xx_dss_feats = {
.model = DSS_MODEL_OMAP2,
/* /*
* fck div max is really 16, but the divider range has gaps. The range * fck div max is really 16, but the divider range has gaps. The range
* from 1 to 6 has no gaps, so let's use that as a max. * from 1 to 6 has no gaps, so let's use that as a max.
*/ */
.fck_div_max = 6, .fck_div_max = 6,
.fck_freq_max = 133000000,
.dss_fck_multiplier = 2, .dss_fck_multiplier = 2,
.parent_clk_name = "core_ck", .parent_clk_name = "core_ck",
.dpi_select_source = &dss_dpi_select_source_omap2_omap3,
.ports = omap2plus_ports, .ports = omap2plus_ports,
.num_ports = ARRAY_SIZE(omap2plus_ports), .num_ports = ARRAY_SIZE(omap2plus_ports),
.outputs = omap2_dss_supported_outputs,
.ops = &dss_ops_omap2_omap3,
.dispc_clk_switch = { 0, 0 },
.has_lcd_clk_src = false,
}; };
static const struct dss_features omap34xx_dss_feats = { static const struct dss_features omap34xx_dss_feats = {
.model = DSS_MODEL_OMAP3,
.fck_div_max = 16, .fck_div_max = 16,
.fck_freq_max = 173000000,
.dss_fck_multiplier = 2, .dss_fck_multiplier = 2,
.parent_clk_name = "dpll4_ck", .parent_clk_name = "dpll4_ck",
.dpi_select_source = &dss_dpi_select_source_omap2_omap3,
.ports = omap34xx_ports, .ports = omap34xx_ports,
.outputs = omap3430_dss_supported_outputs,
.num_ports = ARRAY_SIZE(omap34xx_ports), .num_ports = ARRAY_SIZE(omap34xx_ports),
.ops = &dss_ops_omap2_omap3,
.dispc_clk_switch = { 0, 0 },
.has_lcd_clk_src = false,
}; };
static const struct dss_features omap3630_dss_feats = { static const struct dss_features omap3630_dss_feats = {
.model = DSS_MODEL_OMAP3,
.fck_div_max = 32, .fck_div_max = 32,
.fck_freq_max = 173000000,
.dss_fck_multiplier = 1, .dss_fck_multiplier = 1,
.parent_clk_name = "dpll4_ck", .parent_clk_name = "dpll4_ck",
.dpi_select_source = &dss_dpi_select_source_omap2_omap3,
.ports = omap2plus_ports, .ports = omap2plus_ports,
.num_ports = ARRAY_SIZE(omap2plus_ports), .num_ports = ARRAY_SIZE(omap2plus_ports),
.outputs = omap3630_dss_supported_outputs,
.ops = &dss_ops_omap2_omap3,
.dispc_clk_switch = { 0, 0 },
.has_lcd_clk_src = false,
}; };
static const struct dss_features omap44xx_dss_feats = { static const struct dss_features omap44xx_dss_feats = {
.model = DSS_MODEL_OMAP4,
.fck_div_max = 32, .fck_div_max = 32,
.fck_freq_max = 186000000,
.dss_fck_multiplier = 1, .dss_fck_multiplier = 1,
.parent_clk_name = "dpll_per_x2_ck", .parent_clk_name = "dpll_per_x2_ck",
.dpi_select_source = &dss_dpi_select_source_omap4,
.ports = omap2plus_ports, .ports = omap2plus_ports,
.num_ports = ARRAY_SIZE(omap2plus_ports), .num_ports = ARRAY_SIZE(omap2plus_ports),
.select_lcd_source = &dss_lcd_clk_mux_omap4, .outputs = omap4_dss_supported_outputs,
.ops = &dss_ops_omap4,
.dispc_clk_switch = { 9, 8 },
.has_lcd_clk_src = true,
}; };
static const struct dss_features omap54xx_dss_feats = { static const struct dss_features omap54xx_dss_feats = {
.model = DSS_MODEL_OMAP5,
.fck_div_max = 64, .fck_div_max = 64,
.fck_freq_max = 209250000,
.dss_fck_multiplier = 1, .dss_fck_multiplier = 1,
.parent_clk_name = "dpll_per_x2_ck", .parent_clk_name = "dpll_per_x2_ck",
.dpi_select_source = &dss_dpi_select_source_omap5,
.ports = omap2plus_ports, .ports = omap2plus_ports,
.num_ports = ARRAY_SIZE(omap2plus_ports), .num_ports = ARRAY_SIZE(omap2plus_ports),
.select_lcd_source = &dss_lcd_clk_mux_omap5, .outputs = omap5_dss_supported_outputs,
.ops = &dss_ops_omap5,
.dispc_clk_switch = { 9, 7 },
.has_lcd_clk_src = true,
}; };
static const struct dss_features am43xx_dss_feats = { static const struct dss_features am43xx_dss_feats = {
.model = DSS_MODEL_OMAP3,
.fck_div_max = 0, .fck_div_max = 0,
.fck_freq_max = 200000000,
.dss_fck_multiplier = 0, .dss_fck_multiplier = 0,
.parent_clk_name = NULL, .parent_clk_name = NULL,
.dpi_select_source = &dss_dpi_select_source_omap2_omap3,
.ports = omap2plus_ports, .ports = omap2plus_ports,
.num_ports = ARRAY_SIZE(omap2plus_ports), .num_ports = ARRAY_SIZE(omap2plus_ports),
.outputs = am43xx_dss_supported_outputs,
.ops = &dss_ops_omap2_omap3,
.dispc_clk_switch = { 0, 0 },
.has_lcd_clk_src = true,
}; };
static const struct dss_features dra7xx_dss_feats = { static const struct dss_features dra7xx_dss_feats = {
.model = DSS_MODEL_DRA7,
.fck_div_max = 64, .fck_div_max = 64,
.fck_freq_max = 209250000,
.dss_fck_multiplier = 1, .dss_fck_multiplier = 1,
.parent_clk_name = "dpll_per_x2_ck", .parent_clk_name = "dpll_per_x2_ck",
.dpi_select_source = &dss_dpi_select_source_dra7xx,
.ports = dra7xx_ports, .ports = dra7xx_ports,
.num_ports = ARRAY_SIZE(dra7xx_ports), .num_ports = ARRAY_SIZE(dra7xx_ports),
.select_lcd_source = &dss_lcd_clk_mux_dra7, .outputs = omap5_dss_supported_outputs,
.ops = &dss_ops_dra7,
.dispc_clk_switch = { 9, 7 },
.has_lcd_clk_src = true,
}; };
static int dss_init_features(struct platform_device *pdev)
{
const struct dss_features *src;
struct dss_features *dst;
dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL);
if (!dst) {
dev_err(&pdev->dev, "Failed to allocate local DSS Features\n");
return -ENOMEM;
}
switch (omapdss_get_version()) {
case OMAPDSS_VER_OMAP24xx:
src = &omap24xx_dss_feats;
break;
case OMAPDSS_VER_OMAP34xx_ES1:
case OMAPDSS_VER_OMAP34xx_ES3:
case OMAPDSS_VER_AM35xx:
src = &omap34xx_dss_feats;
break;
case OMAPDSS_VER_OMAP3630:
src = &omap3630_dss_feats;
break;
case OMAPDSS_VER_OMAP4430_ES1:
case OMAPDSS_VER_OMAP4430_ES2:
case OMAPDSS_VER_OMAP4:
src = &omap44xx_dss_feats;
break;
case OMAPDSS_VER_OMAP5:
src = &omap54xx_dss_feats;
break;
case OMAPDSS_VER_AM43xx:
src = &am43xx_dss_feats;
break;
case OMAPDSS_VER_DRA7xx:
src = &dra7xx_dss_feats;
break;
default:
return -ENODEV;
}
memcpy(dst, src, sizeof(*dst));
dss.feat = dst;
return 0;
}
static int dss_init_ports(struct platform_device *pdev) static int dss_init_ports(struct platform_device *pdev)
{ {
struct device_node *parent = pdev->dev.of_node; struct device_node *parent = pdev->dev.of_node;
...@@ -1045,7 +1181,7 @@ static int dss_init_ports(struct platform_device *pdev) ...@@ -1045,7 +1181,7 @@ static int dss_init_ports(struct platform_device *pdev)
switch (dss.feat->ports[i]) { switch (dss.feat->ports[i]) {
case OMAP_DISPLAY_TYPE_DPI: case OMAP_DISPLAY_TYPE_DPI:
dpi_init_port(pdev, port); dpi_init_port(pdev, port, dss.feat->model);
break; break;
case OMAP_DISPLAY_TYPE_SDI: case OMAP_DISPLAY_TYPE_SDI:
sdi_init_port(pdev, port); sdi_init_port(pdev, port);
...@@ -1144,6 +1280,23 @@ static int dss_video_pll_probe(struct platform_device *pdev) ...@@ -1144,6 +1280,23 @@ static int dss_video_pll_probe(struct platform_device *pdev)
} }
/* DSS HW IP initialisation */ /* DSS HW IP initialisation */
static const struct of_device_id dss_of_match[] = {
{ .compatible = "ti,omap2-dss", .data = &omap24xx_dss_feats },
{ .compatible = "ti,omap3-dss", .data = &omap3630_dss_feats },
{ .compatible = "ti,omap4-dss", .data = &omap44xx_dss_feats },
{ .compatible = "ti,omap5-dss", .data = &omap54xx_dss_feats },
{ .compatible = "ti,dra7-dss", .data = &dra7xx_dss_feats },
{},
};
MODULE_DEVICE_TABLE(of, dss_of_match);
static const struct soc_device_attribute dss_soc_devices[] = {
{ .machine = "OMAP3430/3530", .data = &omap34xx_dss_feats },
{ .machine = "AM35??", .data = &omap34xx_dss_feats },
{ .family = "AM43xx", .data = &am43xx_dss_feats },
{ /* sentinel */ }
};
static int dss_bind(struct device *dev) static int dss_bind(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct platform_device *pdev = to_platform_device(dev);
...@@ -1151,12 +1304,6 @@ static int dss_bind(struct device *dev) ...@@ -1151,12 +1304,6 @@ static int dss_bind(struct device *dev)
u32 rev; u32 rev;
int r; int r;
dss.pdev = pdev;
r = dss_init_features(dss.pdev);
if (r)
return r;
dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0); dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0);
dss.base = devm_ioremap_resource(&pdev->dev, dss_mem); dss.base = devm_ioremap_resource(&pdev->dev, dss_mem);
if (IS_ERR(dss.base)) if (IS_ERR(dss.base))
...@@ -1288,15 +1435,34 @@ static int dss_add_child_component(struct device *dev, void *data) ...@@ -1288,15 +1435,34 @@ static int dss_add_child_component(struct device *dev, void *data)
static int dss_probe(struct platform_device *pdev) static int dss_probe(struct platform_device *pdev)
{ {
const struct soc_device_attribute *soc;
struct component_match *match = NULL; struct component_match *match = NULL;
int r; int r;
dss.pdev = pdev;
/*
* The various OMAP3-based SoCs can't be told apart using the compatible
* string, use SoC device matching.
*/
soc = soc_device_match(dss_soc_devices);
if (soc)
dss.feat = soc->data;
else
dss.feat = of_match_device(dss_of_match, &pdev->dev)->data;
r = dss_initialize_debugfs();
if (r)
return r;
/* add all the child devices as components */ /* add all the child devices as components */
device_for_each_child(&pdev->dev, &match, dss_add_child_component); device_for_each_child(&pdev->dev, &match, dss_add_child_component);
r = component_master_add_with_match(&pdev->dev, &dss_component_ops, match); r = component_master_add_with_match(&pdev->dev, &dss_component_ops, match);
if (r) if (r) {
dss_uninitialize_debugfs();
return r; return r;
}
return 0; return 0;
} }
...@@ -1304,9 +1470,27 @@ static int dss_probe(struct platform_device *pdev) ...@@ -1304,9 +1470,27 @@ static int dss_probe(struct platform_device *pdev)
static int dss_remove(struct platform_device *pdev) static int dss_remove(struct platform_device *pdev)
{ {
component_master_del(&pdev->dev, &dss_component_ops); component_master_del(&pdev->dev, &dss_component_ops);
dss_uninitialize_debugfs();
return 0; return 0;
} }
static void dss_shutdown(struct platform_device *pdev)
{
struct omap_dss_device *dssdev = NULL;
DSSDBG("shutdown\n");
for_each_dss_dev(dssdev) {
if (!dssdev->driver)
continue;
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
dssdev->driver->disable(dssdev);
}
}
static int dss_runtime_suspend(struct device *dev) static int dss_runtime_suspend(struct device *dev)
{ {
dss_save_context(); dss_save_context();
...@@ -1343,20 +1527,10 @@ static const struct dev_pm_ops dss_pm_ops = { ...@@ -1343,20 +1527,10 @@ static const struct dev_pm_ops dss_pm_ops = {
.runtime_resume = dss_runtime_resume, .runtime_resume = dss_runtime_resume,
}; };
static const struct of_device_id dss_of_match[] = {
{ .compatible = "ti,omap2-dss", },
{ .compatible = "ti,omap3-dss", },
{ .compatible = "ti,omap4-dss", },
{ .compatible = "ti,omap5-dss", },
{ .compatible = "ti,dra7-dss", },
{},
};
MODULE_DEVICE_TABLE(of, dss_of_match);
static struct platform_driver omap_dsshw_driver = { static struct platform_driver omap_dsshw_driver = {
.probe = dss_probe, .probe = dss_probe,
.remove = dss_remove, .remove = dss_remove,
.shutdown = dss_shutdown,
.driver = { .driver = {
.name = "omapdss_dss", .name = "omapdss_dss",
.pm = &dss_pm_ops, .pm = &dss_pm_ops,
......
...@@ -27,6 +27,9 @@ ...@@ -27,6 +27,9 @@
#include "omapdss.h" #include "omapdss.h"
#define MAX_DSS_LCD_MANAGERS 3
#define MAX_NUM_DSI 2
#ifdef pr_fmt #ifdef pr_fmt
#undef pr_fmt #undef pr_fmt
#endif #endif
...@@ -72,6 +75,14 @@ ...@@ -72,6 +75,14 @@
#define FLD_MOD(orig, val, start, end) \ #define FLD_MOD(orig, val, start, end) \
(((orig) & ~FLD_MASK(start, end)) | FLD_VAL(val, start, end)) (((orig) & ~FLD_MASK(start, end)) | FLD_VAL(val, start, end))
enum dss_model {
DSS_MODEL_OMAP2,
DSS_MODEL_OMAP3,
DSS_MODEL_OMAP4,
DSS_MODEL_OMAP5,
DSS_MODEL_DRA7,
};
enum dss_io_pad_mode { enum dss_io_pad_mode {
DSS_IO_PAD_MODE_RESET, DSS_IO_PAD_MODE_RESET,
DSS_IO_PAD_MODE_RFBI, DSS_IO_PAD_MODE_RFBI,
...@@ -192,6 +203,11 @@ struct dss_pll { ...@@ -192,6 +203,11 @@ struct dss_pll {
struct dss_pll_clock_info cinfo; struct dss_pll_clock_info cinfo;
}; };
/* Defines a generic omap register field */
struct dss_reg_field {
u8 start, end;
};
struct dispc_clock_info { struct dispc_clock_info {
/* rates that we get with dividers below */ /* rates that we get with dividers below */
unsigned long lck; unsigned long lck;
...@@ -219,10 +235,11 @@ struct seq_file; ...@@ -219,10 +235,11 @@ struct seq_file;
struct platform_device; struct platform_device;
/* core */ /* core */
int dss_dsi_enable_pads(int dsi_id, unsigned lane_mask); static inline int dss_set_min_bus_tput(struct device *dev, unsigned long tput)
void dss_dsi_disable_pads(int dsi_id, unsigned lane_mask); {
int dss_set_min_bus_tput(struct device *dev, unsigned long tput); /* To be implemented when the OMAP platform will provide this feature */
int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *)); return 0;
}
static inline bool dss_mgr_is_lcd(enum omap_channel id) static inline bool dss_mgr_is_lcd(enum omap_channel id)
{ {
...@@ -234,6 +251,16 @@ static inline bool dss_mgr_is_lcd(enum omap_channel id) ...@@ -234,6 +251,16 @@ static inline bool dss_mgr_is_lcd(enum omap_channel id)
} }
/* DSS */ /* DSS */
#if defined(CONFIG_OMAP2_DSS_DEBUGFS)
int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *));
#else
static inline int dss_debugfs_create_file(const char *name,
void (*write)(struct seq_file *))
{
return 0;
}
#endif /* CONFIG_OMAP2_DSS_DEBUGFS */
int dss_init_platform_driver(void) __init; int dss_init_platform_driver(void) __init;
void dss_uninit_platform_driver(void); void dss_uninit_platform_driver(void);
...@@ -241,6 +268,8 @@ int dss_runtime_get(void); ...@@ -241,6 +268,8 @@ int dss_runtime_get(void);
void dss_runtime_put(void); void dss_runtime_put(void);
unsigned long dss_get_dispc_clk_rate(void); unsigned long dss_get_dispc_clk_rate(void);
unsigned long dss_get_max_fck_rate(void);
enum omap_dss_output_id dss_get_supported_outputs(enum omap_channel channel);
int dss_dpi_select_source(int port, enum omap_channel channel); int dss_dpi_select_source(int port, enum omap_channel channel);
void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select); void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select);
enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void); enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void);
...@@ -252,10 +281,6 @@ struct dss_pll *dss_video_pll_init(struct platform_device *pdev, int id, ...@@ -252,10 +281,6 @@ struct dss_pll *dss_video_pll_init(struct platform_device *pdev, int id,
struct regulator *regulator); struct regulator *regulator);
void dss_video_pll_uninit(struct dss_pll *pll); void dss_video_pll_uninit(struct dss_pll *pll);
#if defined(CONFIG_OMAP2_DSS_DEBUGFS)
void dss_debug_dump_clocks(struct seq_file *s);
#endif
void dss_ctrl_pll_enable(enum dss_pll_id pll_id, bool enable); void dss_ctrl_pll_enable(enum dss_pll_id pll_id, bool enable);
void dss_sdi_init(int datapairs); void dss_sdi_init(int datapairs);
...@@ -312,11 +337,12 @@ void dsi_irq_handler(void); ...@@ -312,11 +337,12 @@ void dsi_irq_handler(void);
/* DPI */ /* DPI */
#ifdef CONFIG_OMAP2_DSS_DPI #ifdef CONFIG_OMAP2_DSS_DPI
int dpi_init_port(struct platform_device *pdev, struct device_node *port); int dpi_init_port(struct platform_device *pdev, struct device_node *port,
enum dss_model dss_model);
void dpi_uninit_port(struct device_node *port); void dpi_uninit_port(struct device_node *port);
#else #else
static inline int dpi_init_port(struct platform_device *pdev, static inline int dpi_init_port(struct platform_device *pdev,
struct device_node *port) struct device_node *port, enum dss_model dss_model)
{ {
return 0; return 0;
} }
......
此差异已折叠。
/*
* linux/drivers/video/omap2/dss/dss_features.h
*
* Copyright (C) 2010 Texas Instruments
* Author: Archit Taneja <archit@ti.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/>.
*/
#ifndef __OMAP2_DSS_FEATURES_H
#define __OMAP2_DSS_FEATURES_H
#define MAX_DSS_MANAGERS 4
#define MAX_DSS_OVERLAYS 4
#define MAX_DSS_LCD_MANAGERS 3
#define MAX_NUM_DSI 2
/* DSS has feature id */
enum dss_feat_id {
FEAT_LCDENABLEPOL,
FEAT_LCDENABLESIGNAL,
FEAT_PCKFREEENABLE,
FEAT_FUNCGATED,
FEAT_MGR_LCD2,
FEAT_MGR_LCD3,
FEAT_LINEBUFFERSPLIT,
FEAT_ROWREPEATENABLE,
FEAT_RESIZECONF,
/* Independent core clk divider */
FEAT_CORE_CLK_DIV,
FEAT_LCD_CLK_SRC,
/* DSI-PLL power command 0x3 is not working */
FEAT_DSI_PLL_PWR_BUG,
FEAT_DSI_DCS_CMD_CONFIG_VC,
FEAT_DSI_VC_OCP_WIDTH,
FEAT_DSI_REVERSE_TXCLKESC,
FEAT_DSI_GNQ,
FEAT_DPI_USES_VDDS_DSI,
FEAT_HDMI_CTS_SWMODE,
FEAT_HDMI_AUDIO_USE_MCLK,
FEAT_HANDLE_UV_SEPARATE,
FEAT_ATTR2,
FEAT_VENC_REQUIRES_TV_DAC_CLK,
FEAT_CPR,
FEAT_PRELOAD,
FEAT_FIR_COEF_V,
FEAT_ALPHA_FIXED_ZORDER,
FEAT_ALPHA_FREE_ZORDER,
FEAT_FIFO_MERGE,
/* An unknown HW bug causing the normal FIFO thresholds not to work */
FEAT_OMAP3_DSI_FIFO_BUG,
FEAT_BURST_2D,
FEAT_DSI_PHY_DCC,
FEAT_MFLAG,
};
/* DSS register field id */
enum dss_feat_reg_field {
FEAT_REG_FIRHINC,
FEAT_REG_FIRVINC,
FEAT_REG_FIFOHIGHTHRESHOLD,
FEAT_REG_FIFOLOWTHRESHOLD,
FEAT_REG_FIFOSIZE,
FEAT_REG_HORIZONTALACCU,
FEAT_REG_VERTICALACCU,
FEAT_REG_DISPC_CLK_SWITCH,
};
enum dss_range_param {
FEAT_PARAM_DSS_FCK,
FEAT_PARAM_DSS_PCD,
FEAT_PARAM_DSIPLL_LPDIV,
FEAT_PARAM_DSI_FCK,
FEAT_PARAM_DOWNSCALE,
FEAT_PARAM_LINEWIDTH,
};
/* DSS Feature Functions */
unsigned long dss_feat_get_param_min(enum dss_range_param param);
unsigned long dss_feat_get_param_max(enum dss_range_param param);
enum omap_overlay_caps dss_feat_get_overlay_caps(enum omap_plane_id plane);
bool dss_feat_color_mode_supported(enum omap_plane_id plane,
u32 fourcc);
u32 dss_feat_get_buffer_size_unit(void); /* in bytes */
u32 dss_feat_get_burst_size_unit(void); /* in bytes */
bool dss_has_feature(enum dss_feat_id id);
void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end);
void dss_features_init(enum omapdss_version version);
enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel);
enum omap_dss_output_id dss_feat_get_supported_outputs(enum omap_channel channel);
int dss_feat_get_num_mgrs(void);
int dss_feat_get_num_ovls(void);
const u32 *dss_feat_get_supported_color_modes(enum omap_plane_id plane);
#endif
...@@ -234,6 +234,7 @@ struct hdmi_core_audio_config { ...@@ -234,6 +234,7 @@ struct hdmi_core_audio_config {
struct hdmi_wp_data { struct hdmi_wp_data {
void __iomem *base; void __iomem *base;
phys_addr_t phys_base; phys_addr_t phys_base;
unsigned int version;
}; };
struct hdmi_pll_data { struct hdmi_pll_data {
...@@ -245,15 +246,24 @@ struct hdmi_pll_data { ...@@ -245,15 +246,24 @@ struct hdmi_pll_data {
struct hdmi_wp_data *wp; struct hdmi_wp_data *wp;
}; };
struct hdmi_phy_features {
bool bist_ctrl;
bool ldo_voltage;
unsigned long max_phy;
};
struct hdmi_phy_data { struct hdmi_phy_data {
void __iomem *base; void __iomem *base;
const struct hdmi_phy_features *features;
u8 lane_function[4]; u8 lane_function[4];
u8 lane_polarity[4]; u8 lane_polarity[4];
}; };
struct hdmi_core_data { struct hdmi_core_data {
void __iomem *base; void __iomem *base;
bool cts_swmode;
bool audio_use_mclk;
}; };
static inline void hdmi_write_reg(void __iomem *base_addr, const u32 idx, static inline void hdmi_write_reg(void __iomem *base_addr, const u32 idx,
...@@ -303,7 +313,8 @@ void hdmi_wp_video_config_timing(struct hdmi_wp_data *wp, ...@@ -303,7 +313,8 @@ void hdmi_wp_video_config_timing(struct hdmi_wp_data *wp,
struct videomode *vm); struct videomode *vm);
void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt, void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt,
struct videomode *vm, struct hdmi_config *param); struct videomode *vm, struct hdmi_config *param);
int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp); int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp,
unsigned int version);
phys_addr_t hdmi_wp_get_audio_dma_addr(struct hdmi_wp_data *wp); phys_addr_t hdmi_wp_get_audio_dma_addr(struct hdmi_wp_data *wp);
/* HDMI PLL funcs */ /* HDMI PLL funcs */
...@@ -316,7 +327,8 @@ void hdmi_pll_uninit(struct hdmi_pll_data *hpll); ...@@ -316,7 +327,8 @@ void hdmi_pll_uninit(struct hdmi_pll_data *hpll);
int hdmi_phy_configure(struct hdmi_phy_data *phy, unsigned long hfbitclk, int hdmi_phy_configure(struct hdmi_phy_data *phy, unsigned long hfbitclk,
unsigned long lfbitclk); unsigned long lfbitclk);
void hdmi_phy_dump(struct hdmi_phy_data *phy, struct seq_file *s); void hdmi_phy_dump(struct hdmi_phy_data *phy, struct seq_file *s);
int hdmi_phy_init(struct platform_device *pdev, struct hdmi_phy_data *phy); int hdmi_phy_init(struct platform_device *pdev, struct hdmi_phy_data *phy,
unsigned int version);
int hdmi_phy_parse_lanes(struct hdmi_phy_data *phy, const u32 *lanes); int hdmi_phy_parse_lanes(struct hdmi_phy_data *phy, const u32 *lanes);
/* HDMI common funcs */ /* HDMI common funcs */
......
...@@ -40,7 +40,6 @@ ...@@ -40,7 +40,6 @@
#include "omapdss.h" #include "omapdss.h"
#include "hdmi4_core.h" #include "hdmi4_core.h"
#include "dss.h" #include "dss.h"
#include "dss_features.h"
#include "hdmi.h" #include "hdmi.h"
static struct omap_hdmi hdmi; static struct omap_hdmi hdmi;
...@@ -668,7 +667,7 @@ static int hdmi_audio_register(struct device *dev) ...@@ -668,7 +667,7 @@ static int hdmi_audio_register(struct device *dev)
{ {
struct omap_hdmi_audio_pdata pdata = { struct omap_hdmi_audio_pdata pdata = {
.dev = dev, .dev = dev,
.dss_version = omapdss_get_version(), .version = 4,
.audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi.wp), .audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi.wp),
.ops = &hdmi_audio_ops, .ops = &hdmi_audio_ops,
}; };
...@@ -700,7 +699,7 @@ static int hdmi4_bind(struct device *dev, struct device *master, void *data) ...@@ -700,7 +699,7 @@ static int hdmi4_bind(struct device *dev, struct device *master, void *data)
if (r) if (r)
return r; return r;
r = hdmi_wp_init(pdev, &hdmi.wp); r = hdmi_wp_init(pdev, &hdmi.wp, 4);
if (r) if (r)
return r; return r;
...@@ -708,7 +707,7 @@ static int hdmi4_bind(struct device *dev, struct device *master, void *data) ...@@ -708,7 +707,7 @@ static int hdmi4_bind(struct device *dev, struct device *master, void *data)
if (r) if (r)
return r; return r;
r = hdmi_phy_init(pdev, &hdmi.phy); r = hdmi_phy_init(pdev, &hdmi.phy, 4);
if (r) if (r)
goto err; goto err;
......
...@@ -31,11 +31,11 @@ ...@@ -31,11 +31,11 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/sys_soc.h>
#include <sound/asound.h> #include <sound/asound.h>
#include <sound/asoundef.h> #include <sound/asoundef.h>
#include "hdmi4_core.h" #include "hdmi4_core.h"
#include "dss_features.h"
#define HDMI_CORE_AV 0x500 #define HDMI_CORE_AV 0x500
...@@ -757,10 +757,10 @@ int hdmi4_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp, ...@@ -757,10 +757,10 @@ int hdmi4_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
/* Audio clock regeneration settings */ /* Audio clock regeneration settings */
acore.n = n; acore.n = n;
acore.cts = cts; acore.cts = cts;
if (dss_has_feature(FEAT_HDMI_CTS_SWMODE)) { if (core->cts_swmode) {
acore.aud_par_busclk = 0; acore.aud_par_busclk = 0;
acore.cts_mode = HDMI_AUDIO_CTS_MODE_SW; acore.cts_mode = HDMI_AUDIO_CTS_MODE_SW;
acore.use_mclk = dss_has_feature(FEAT_HDMI_AUDIO_USE_MCLK); acore.use_mclk = core->audio_use_mclk;
} else { } else {
acore.aud_par_busclk = (((128 * 31) - 1) << 8); acore.aud_par_busclk = (((128 * 31) - 1) << 8);
acore.cts_mode = HDMI_AUDIO_CTS_MODE_HW; acore.cts_mode = HDMI_AUDIO_CTS_MODE_HW;
...@@ -884,10 +884,42 @@ void hdmi4_audio_stop(struct hdmi_core_data *core, struct hdmi_wp_data *wp) ...@@ -884,10 +884,42 @@ void hdmi4_audio_stop(struct hdmi_core_data *core, struct hdmi_wp_data *wp)
hdmi_wp_audio_core_req_enable(wp, false); hdmi_wp_audio_core_req_enable(wp, false);
} }
struct hdmi4_features {
bool cts_swmode;
bool audio_use_mclk;
};
static const struct hdmi4_features hdmi4_es1_features = {
.cts_swmode = false,
.audio_use_mclk = false,
};
static const struct hdmi4_features hdmi4_es2_features = {
.cts_swmode = true,
.audio_use_mclk = false,
};
static const struct hdmi4_features hdmi4_es3_features = {
.cts_swmode = true,
.audio_use_mclk = true,
};
static const struct soc_device_attribute hdmi4_soc_devices[] = {
{ .family = "OMAP4", .revision = "ES1.?", .data = &hdmi4_es1_features },
{ .family = "OMAP4", .revision = "ES2.?", .data = &hdmi4_es2_features },
{ .family = "OMAP4", .data = &hdmi4_es3_features },
{ /* sentinel */ }
};
int hdmi4_core_init(struct platform_device *pdev, struct hdmi_core_data *core) int hdmi4_core_init(struct platform_device *pdev, struct hdmi_core_data *core)
{ {
const struct hdmi4_features *features;
struct resource *res; struct resource *res;
features = soc_device_match(hdmi4_soc_devices)->data;
core->cts_swmode = features->cts_swmode;
core->audio_use_mclk = features->audio_use_mclk;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core"); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core");
core->base = devm_ioremap_resource(&pdev->dev, res); core->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(core->base)) if (IS_ERR(core->base))
......
...@@ -45,7 +45,6 @@ ...@@ -45,7 +45,6 @@
#include "omapdss.h" #include "omapdss.h"
#include "hdmi5_core.h" #include "hdmi5_core.h"
#include "dss.h" #include "dss.h"
#include "dss_features.h"
static struct omap_hdmi hdmi; static struct omap_hdmi hdmi;
...@@ -695,7 +694,7 @@ static int hdmi_audio_register(struct device *dev) ...@@ -695,7 +694,7 @@ static int hdmi_audio_register(struct device *dev)
{ {
struct omap_hdmi_audio_pdata pdata = { struct omap_hdmi_audio_pdata pdata = {
.dev = dev, .dev = dev,
.dss_version = omapdss_get_version(), .version = 5,
.audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi.wp), .audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi.wp),
.ops = &hdmi_audio_ops, .ops = &hdmi_audio_ops,
}; };
...@@ -732,7 +731,7 @@ static int hdmi5_bind(struct device *dev, struct device *master, void *data) ...@@ -732,7 +731,7 @@ static int hdmi5_bind(struct device *dev, struct device *master, void *data)
if (r) if (r)
return r; return r;
r = hdmi_wp_init(pdev, &hdmi.wp); r = hdmi_wp_init(pdev, &hdmi.wp, 5);
if (r) if (r)
return r; return r;
...@@ -740,7 +739,7 @@ static int hdmi5_bind(struct device *dev, struct device *master, void *data) ...@@ -740,7 +739,7 @@ static int hdmi5_bind(struct device *dev, struct device *master, void *data)
if (r) if (r)
return r; return r;
r = hdmi_phy_init(pdev, &hdmi.phy); r = hdmi_phy_init(pdev, &hdmi.phy, 5);
if (r) if (r)
goto err; goto err;
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册