提交 3315764e 编写于 作者: T Tomi Valkeinen

Merge branches '3.19/omapdss' and '3.19/simplefb' into fbdev

Merge fbdev topic branches.
Sunxi specific Simple Framebuffer bindings
This binding documents sunxi specific extensions to the simple-framebuffer
bindings. The sunxi simplefb u-boot code relies on the devicetree containing
pre-populated simplefb nodes.
These extensions are intended so that u-boot can select the right node based
on which pipeline is being used. As such they are solely intended for
firmware / bootloader use, and the OS should ignore them.
Required properties:
- compatible: "allwinner,simple-framebuffer"
- allwinner,pipeline, one of:
"de_be0-lcd0"
"de_be1-lcd1"
"de_be0-lcd0-hdmi"
"de_be1-lcd1-hdmi"
Example:
chosen {
#address-cells = <1>;
#size-cells = <1>;
ranges;
framebuffer@0 {
compatible = "allwinner,simple-framebuffer", "simple-framebuffer";
allwinner,pipeline = "de_be0-lcd0-hdmi";
clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 43>,
<&ahb_gates 44>;
status = "disabled";
};
};
Simple Framebuffer Simple Framebuffer
A simple frame-buffer describes a raw memory region that may be rendered to, A simple frame-buffer describes a frame-buffer setup by firmware or
with the assumption that the display hardware has already been set up to scan the bootloader, with the assumption that the display hardware has already
out from that buffer. been set up to scan out from the memory pointed to by the reg property.
Since simplefb nodes represent runtime information they must be sub-nodes of
the chosen node (*). Simplefb nodes must be named "framebuffer@<address>".
If the devicetree contains nodes for the display hardware used by a simplefb,
then the simplefb node must contain a property called "display", which
contains a phandle pointing to the primary display hw node, so that the OS
knows which simplefb to disable when handing over control to a driver for the
real hardware. The bindings for the hw nodes must specify which node is
considered the primary node.
It is advised to add display# aliases to help the OS determine how to number
things. If display# aliases are used, then if the simplefb node contains a
"display" property then the /aliases/display# path must point to the display
hw node the "display" property points to, otherwise it must point directly
to the simplefb node.
If a simplefb node represents the preferred console for user interaction,
then the chosen node's stdout-path property should point to it, or to the
primary display hw node, as with display# aliases. If display aliases are
used then it should be set to the alias instead.
It is advised that devicetree files contain pre-filled, disabled framebuffer
nodes, so that the firmware only needs to update the mode information and
enable them. This way if e.g. later on support for more display clocks get
added, the simplefb nodes will already contain this info and the firmware
does not need to be updated.
If pre-filled framebuffer nodes are used, the firmware may need extra
information to find the right node. In that case an extra platform specific
compatible and platform specific properties should be used and documented,
see e.g. simple-framebuffer-sunxi.txt .
Required properties: Required properties:
- compatible: "simple-framebuffer" - compatible: "simple-framebuffer"
...@@ -14,13 +46,41 @@ Required properties: ...@@ -14,13 +46,41 @@ Required properties:
- r5g6b5 (16-bit pixels, d[15:11]=r, d[10:5]=g, d[4:0]=b). - r5g6b5 (16-bit pixels, d[15:11]=r, d[10:5]=g, d[4:0]=b).
- a8b8g8r8 (32-bit pixels, d[31:24]=a, d[23:16]=b, d[15:8]=g, d[7:0]=r). - a8b8g8r8 (32-bit pixels, d[31:24]=a, d[23:16]=b, d[15:8]=g, d[7:0]=r).
Optional properties:
- clocks : List of clocks used by the framebuffer. Clocks listed here
are expected to already be configured correctly. The OS must
ensure these clocks are not modified or disabled while the
simple framebuffer remains active.
- display : phandle pointing to the primary display hardware node
Example: Example:
framebuffer { aliases {
display0 = &lcdc0;
}
chosen {
framebuffer0: framebuffer@1d385000 {
compatible = "simple-framebuffer"; compatible = "simple-framebuffer";
reg = <0x1d385000 (1600 * 1200 * 2)>; reg = <0x1d385000 (1600 * 1200 * 2)>;
width = <1600>; width = <1600>;
height = <1200>; height = <1200>;
stride = <(1600 * 2)>; stride = <(1600 * 2)>;
format = "r5g6b5"; format = "r5g6b5";
clocks = <&ahb_gates 36>, <&ahb_gates 43>, <&ahb_gates 44>;
display = <&lcdc0>;
};
stdout-path = "display0";
};
soc@01c00000 {
lcdc0: lcdc@1c0c000 {
compatible = "allwinner,sun4i-a10-lcdc";
...
}; };
};
*) Older devicetree files may have a compatible = "simple-framebuffer" node
in a different place, operating systems must first enumerate any compatible
nodes found under chosen and then check for other compatible nodes.
...@@ -8442,6 +8442,14 @@ F: drivers/media/usb/siano/ ...@@ -8442,6 +8442,14 @@ F: drivers/media/usb/siano/
F: drivers/media/usb/siano/ F: drivers/media/usb/siano/
F: drivers/media/mmc/siano/ F: drivers/media/mmc/siano/
SIMPLEFB FB DRIVER
M: Hans de Goede <hdegoede@redhat.com>
L: linux-fbdev@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/video/simple-framebuffer.txt
F: drivers/video/fbdev/simplefb.c
F: include/linux/platform_data/simplefb.h
SH_VEU V4L2 MEM2MEM DRIVER SH_VEU V4L2 MEM2MEM DRIVER
L: linux-media@vger.kernel.org L: linux-media@vger.kernel.org
S: Orphan S: Orphan
......
...@@ -3624,7 +3624,7 @@ static int __init fb_console_init(void) ...@@ -3624,7 +3624,7 @@ static int __init fb_console_init(void)
return 0; return 0;
} }
module_init(fb_console_init); fs_initcall(fb_console_init);
#ifdef MODULE #ifdef MODULE
......
...@@ -170,98 +170,6 @@ static bool hdmic_detect(struct omap_dss_device *dssdev) ...@@ -170,98 +170,6 @@ static bool hdmic_detect(struct omap_dss_device *dssdev)
return in->ops.hdmi->detect(in); return in->ops.hdmi->detect(in);
} }
static int hdmic_audio_enable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
int r;
/* enable audio only if the display is active */
if (!omapdss_device_is_enabled(dssdev))
return -EPERM;
r = in->ops.hdmi->audio_enable(in);
if (r)
return r;
dssdev->audio_state = OMAP_DSS_AUDIO_ENABLED;
return 0;
}
static void hdmic_audio_disable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
in->ops.hdmi->audio_disable(in);
dssdev->audio_state = OMAP_DSS_AUDIO_DISABLED;
}
static int hdmic_audio_start(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
int r;
/*
* No need to check the panel state. It was checked when trasitioning
* to AUDIO_ENABLED.
*/
if (dssdev->audio_state != OMAP_DSS_AUDIO_ENABLED)
return -EPERM;
r = in->ops.hdmi->audio_start(in);
if (r)
return r;
dssdev->audio_state = OMAP_DSS_AUDIO_PLAYING;
return 0;
}
static void hdmic_audio_stop(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
in->ops.hdmi->audio_stop(in);
dssdev->audio_state = OMAP_DSS_AUDIO_ENABLED;
}
static bool hdmic_audio_supported(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
if (!omapdss_device_is_enabled(dssdev))
return false;
return in->ops.hdmi->audio_supported(in);
}
static int hdmic_audio_config(struct omap_dss_device *dssdev,
struct omap_dss_audio *audio)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
int r;
/* config audio only if the display is active */
if (!omapdss_device_is_enabled(dssdev))
return -EPERM;
r = in->ops.hdmi->audio_config(in, audio);
if (r)
return r;
dssdev->audio_state = OMAP_DSS_AUDIO_CONFIGURED;
return 0;
}
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);
...@@ -296,13 +204,6 @@ static struct omap_dss_driver hdmic_driver = { ...@@ -296,13 +204,6 @@ static struct omap_dss_driver hdmic_driver = {
.detect = hdmic_detect, .detect = hdmic_detect,
.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,
.audio_enable = hdmic_audio_enable,
.audio_disable = hdmic_audio_disable,
.audio_start = hdmic_audio_start,
.audio_stop = hdmic_audio_stop,
.audio_supported = hdmic_audio_supported,
.audio_config = hdmic_audio_config,
}; };
static int hdmic_probe_pdata(struct platform_device *pdev) static int hdmic_probe_pdata(struct platform_device *pdev)
......
...@@ -249,6 +249,7 @@ static int tfp410_probe(struct platform_device *pdev) ...@@ -249,6 +249,7 @@ static int tfp410_probe(struct platform_device *pdev)
dssdev->output_type = OMAP_DISPLAY_TYPE_DVI; dssdev->output_type = OMAP_DISPLAY_TYPE_DVI;
dssdev->owner = THIS_MODULE; dssdev->owner = THIS_MODULE;
dssdev->phy.dpi.data_lines = ddata->data_lines; dssdev->phy.dpi.data_lines = ddata->data_lines;
dssdev->port_num = 1;
r = omapdss_register_output(dssdev); r = omapdss_register_output(dssdev);
if (r) { if (r) {
......
...@@ -193,55 +193,6 @@ static bool tpd_detect(struct omap_dss_device *dssdev) ...@@ -193,55 +193,6 @@ static bool tpd_detect(struct omap_dss_device *dssdev)
return gpio_get_value_cansleep(ddata->hpd_gpio); return gpio_get_value_cansleep(ddata->hpd_gpio);
} }
static int tpd_audio_enable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
return in->ops.hdmi->audio_enable(in);
}
static void tpd_audio_disable(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
in->ops.hdmi->audio_disable(in);
}
static int tpd_audio_start(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
return in->ops.hdmi->audio_start(in);
}
static void tpd_audio_stop(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
in->ops.hdmi->audio_stop(in);
}
static bool tpd_audio_supported(struct omap_dss_device *dssdev)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
return in->ops.hdmi->audio_supported(in);
}
static int tpd_audio_config(struct omap_dss_device *dssdev,
struct omap_dss_audio *audio)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
return in->ops.hdmi->audio_config(in, audio);
}
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)
{ {
...@@ -275,13 +226,6 @@ static const struct omapdss_hdmi_ops tpd_hdmi_ops = { ...@@ -275,13 +226,6 @@ static const struct omapdss_hdmi_ops tpd_hdmi_ops = {
.detect = tpd_detect, .detect = tpd_detect,
.set_infoframe = tpd_set_infoframe, .set_infoframe = tpd_set_infoframe,
.set_hdmi_mode = tpd_set_hdmi_mode, .set_hdmi_mode = tpd_set_hdmi_mode,
.audio_enable = tpd_audio_enable,
.audio_disable = tpd_audio_disable,
.audio_start = tpd_audio_start,
.audio_stop = tpd_audio_stop,
.audio_supported = tpd_audio_supported,
.audio_config = tpd_audio_config,
}; };
static int tpd_probe_pdata(struct platform_device *pdev) static int tpd_probe_pdata(struct platform_device *pdev)
...@@ -409,6 +353,7 @@ static int tpd_probe(struct platform_device *pdev) ...@@ -409,6 +353,7 @@ static int tpd_probe(struct platform_device *pdev)
dssdev->type = OMAP_DISPLAY_TYPE_HDMI; dssdev->type = OMAP_DISPLAY_TYPE_HDMI;
dssdev->output_type = OMAP_DISPLAY_TYPE_HDMI; dssdev->output_type = OMAP_DISPLAY_TYPE_HDMI;
dssdev->owner = THIS_MODULE; dssdev->owner = THIS_MODULE;
dssdev->port_num = 1;
in = ddata->in; in = ddata->in;
......
...@@ -74,9 +74,6 @@ config OMAP4_DSS_HDMI ...@@ -74,9 +74,6 @@ config OMAP4_DSS_HDMI
help help
HDMI support for OMAP4 based SoCs. HDMI support for OMAP4 based SoCs.
config OMAP4_DSS_HDMI_AUDIO
bool
config OMAP5_DSS_HDMI config OMAP5_DSS_HDMI
bool "HDMI support for OMAP5" bool "HDMI support for OMAP5"
default n default n
...@@ -86,10 +83,6 @@ config OMAP5_DSS_HDMI ...@@ -86,10 +83,6 @@ config OMAP5_DSS_HDMI
Definition Multimedia Interface. See http://www.hdmi.org/ for HDMI Definition Multimedia Interface. See http://www.hdmi.org/ for HDMI
specification. specification.
config OMAP5_DSS_HDMI_AUDIO
depends on OMAP5_DSS_HDMI
bool
config OMAP2_DSS_SDI config OMAP2_DSS_SDI
bool "SDI support" bool "SDI support"
default n default n
......
...@@ -2,7 +2,7 @@ obj-$(CONFIG_OMAP2_DSS_INIT) += omapdss-boot-init.o ...@@ -2,7 +2,7 @@ obj-$(CONFIG_OMAP2_DSS_INIT) += omapdss-boot-init.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 display.o \ omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \
output.o dss-of.o output.o dss-of.o pll.o
# DSS compat layer files # DSS compat layer files
omapdss-y += manager.o manager-sysfs.o overlay.o overlay-sysfs.o apply.o \ omapdss-y += manager.o manager-sysfs.o overlay.o overlay-sysfs.o apply.o \
dispc-compat.o display-sysfs.o dispc-compat.o display-sysfs.o
......
...@@ -3028,7 +3028,7 @@ static void dispc_mgr_get_lcd_divisor(enum omap_channel channel, int *lck_div, ...@@ -3028,7 +3028,7 @@ static void dispc_mgr_get_lcd_divisor(enum omap_channel channel, int *lck_div,
unsigned long dispc_fclk_rate(void) unsigned long dispc_fclk_rate(void)
{ {
struct platform_device *dsidev; struct dss_pll *pll;
unsigned long r = 0; unsigned long r = 0;
switch (dss_get_dispc_clk_source()) { switch (dss_get_dispc_clk_source()) {
...@@ -3036,12 +3036,12 @@ unsigned long dispc_fclk_rate(void) ...@@ -3036,12 +3036,12 @@ unsigned long dispc_fclk_rate(void)
r = dss_get_dispc_clk_rate(); r = dss_get_dispc_clk_rate();
break; break;
case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
dsidev = dsi_get_dsidev_from_id(0); pll = dss_pll_find("dsi0");
r = dsi_get_pll_hsdiv_dispc_rate(dsidev); r = pll->cinfo.clkout[0];
break; break;
case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC: case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
dsidev = dsi_get_dsidev_from_id(1); pll = dss_pll_find("dsi1");
r = dsi_get_pll_hsdiv_dispc_rate(dsidev); r = pll->cinfo.clkout[0];
break; break;
default: default:
BUG(); BUG();
...@@ -3053,7 +3053,7 @@ unsigned long dispc_fclk_rate(void) ...@@ -3053,7 +3053,7 @@ unsigned long dispc_fclk_rate(void)
unsigned long dispc_mgr_lclk_rate(enum omap_channel channel) unsigned long dispc_mgr_lclk_rate(enum omap_channel channel)
{ {
struct platform_device *dsidev; struct dss_pll *pll;
int lcd; int lcd;
unsigned long r; unsigned long r;
u32 l; u32 l;
...@@ -3068,12 +3068,12 @@ unsigned long dispc_mgr_lclk_rate(enum omap_channel channel) ...@@ -3068,12 +3068,12 @@ unsigned long dispc_mgr_lclk_rate(enum omap_channel channel)
r = dss_get_dispc_clk_rate(); r = dss_get_dispc_clk_rate();
break; break;
case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
dsidev = dsi_get_dsidev_from_id(0); pll = dss_pll_find("dsi0");
r = dsi_get_pll_hsdiv_dispc_rate(dsidev); r = pll->cinfo.clkout[0];
break; break;
case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC: case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
dsidev = dsi_get_dsidev_from_id(1); pll = dss_pll_find("dsi1");
r = dsi_get_pll_hsdiv_dispc_rate(dsidev); r = pll->cinfo.clkout[0];
break; break;
default: default:
BUG(); BUG();
......
...@@ -31,17 +31,20 @@ ...@@ -31,17 +31,20 @@
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/clk.h>
#include <video/omapdss.h> #include <video/omapdss.h>
#include "dss.h" #include "dss.h"
#include "dss_features.h" #include "dss_features.h"
static struct { #define HSDIV_DISPC 0
struct dpi_data {
struct platform_device *pdev; struct platform_device *pdev;
struct regulator *vdds_dsi_reg; struct regulator *vdds_dsi_reg;
struct platform_device *dsidev; struct dss_pll *pll;
struct mutex lock; struct mutex lock;
...@@ -52,9 +55,20 @@ static struct { ...@@ -52,9 +55,20 @@ static struct {
struct omap_dss_device output; struct omap_dss_device output;
bool port_initialized; bool port_initialized;
} dpi; };
static struct dpi_data *dpi_get_data_from_dssdev(struct omap_dss_device *dssdev)
{
return container_of(dssdev, struct dpi_data, output);
}
/* only used in non-DT mode */
static struct dpi_data *dpi_get_data_from_pdev(struct platform_device *pdev)
{
return dev_get_drvdata(&pdev->dev);
}
static struct platform_device *dpi_get_dsidev(enum omap_channel channel) static struct dss_pll *dpi_get_pll(enum omap_channel 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
...@@ -75,9 +89,9 @@ static struct platform_device *dpi_get_dsidev(enum omap_channel channel) ...@@ -75,9 +89,9 @@ static struct platform_device *dpi_get_dsidev(enum omap_channel channel)
case OMAPDSS_VER_OMAP4: case OMAPDSS_VER_OMAP4:
switch (channel) { switch (channel) {
case OMAP_DSS_CHANNEL_LCD: case OMAP_DSS_CHANNEL_LCD:
return dsi_get_dsidev_from_id(0); return dss_pll_find("dsi0");
case OMAP_DSS_CHANNEL_LCD2: case OMAP_DSS_CHANNEL_LCD2:
return dsi_get_dsidev_from_id(1); return dss_pll_find("dsi1");
default: default:
return NULL; return NULL;
} }
...@@ -85,9 +99,9 @@ static struct platform_device *dpi_get_dsidev(enum omap_channel channel) ...@@ -85,9 +99,9 @@ static struct platform_device *dpi_get_dsidev(enum omap_channel channel)
case OMAPDSS_VER_OMAP5: case OMAPDSS_VER_OMAP5:
switch (channel) { switch (channel) {
case OMAP_DSS_CHANNEL_LCD: case OMAP_DSS_CHANNEL_LCD:
return dsi_get_dsidev_from_id(0); return dss_pll_find("dsi0");
case OMAP_DSS_CHANNEL_LCD3: case OMAP_DSS_CHANNEL_LCD3:
return dsi_get_dsidev_from_id(1); return dss_pll_find("dsi1");
default: default:
return NULL; return NULL;
} }
...@@ -114,7 +128,7 @@ static enum omap_dss_clk_source dpi_get_alt_clk_src(enum omap_channel channel) ...@@ -114,7 +128,7 @@ static enum omap_dss_clk_source dpi_get_alt_clk_src(enum omap_channel channel)
} }
struct dpi_clk_calc_ctx { struct dpi_clk_calc_ctx {
struct platform_device *dsidev; struct dss_pll *pll;
/* inputs */ /* inputs */
...@@ -122,7 +136,7 @@ struct dpi_clk_calc_ctx { ...@@ -122,7 +136,7 @@ struct dpi_clk_calc_ctx {
/* outputs */ /* outputs */
struct dsi_clock_info dsi_cinfo; struct dss_pll_clock_info dsi_cinfo;
unsigned long fck; unsigned long fck;
struct dispc_clock_info dispc_cinfo; struct dispc_clock_info dispc_cinfo;
}; };
...@@ -154,7 +168,7 @@ static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck, ...@@ -154,7 +168,7 @@ static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
} }
static bool dpi_calc_hsdiv_cb(int regm_dispc, unsigned long dispc, static bool dpi_calc_hsdiv_cb(int m_dispc, unsigned long dispc,
void *data) void *data)
{ {
struct dpi_clk_calc_ctx *ctx = data; struct dpi_clk_calc_ctx *ctx = data;
...@@ -164,30 +178,31 @@ static bool dpi_calc_hsdiv_cb(int regm_dispc, unsigned long dispc, ...@@ -164,30 +178,31 @@ static bool dpi_calc_hsdiv_cb(int regm_dispc, unsigned long dispc,
* shifted. So skip all odd dividers when the pixel clock is on the * shifted. So skip all odd dividers when the pixel clock is on the
* higher side. * higher side.
*/ */
if (regm_dispc > 1 && regm_dispc % 2 != 0 && ctx->pck_min >= 100000000) if (m_dispc > 1 && m_dispc % 2 != 0 && ctx->pck_min >= 100000000)
return false; return false;
ctx->dsi_cinfo.regm_dispc = regm_dispc; ctx->dsi_cinfo.mX[HSDIV_DISPC] = m_dispc;
ctx->dsi_cinfo.dsi_pll_hsdiv_dispc_clk = dispc; ctx->dsi_cinfo.clkout[HSDIV_DISPC] = dispc;
return dispc_div_calc(dispc, ctx->pck_min, ctx->pck_max, return dispc_div_calc(dispc, ctx->pck_min, ctx->pck_max,
dpi_calc_dispc_cb, ctx); dpi_calc_dispc_cb, ctx);
} }
static bool dpi_calc_pll_cb(int regn, int regm, unsigned long fint, static bool dpi_calc_pll_cb(int n, int m, unsigned long fint,
unsigned long pll, unsigned long clkdco,
void *data) void *data)
{ {
struct dpi_clk_calc_ctx *ctx = data; struct dpi_clk_calc_ctx *ctx = data;
ctx->dsi_cinfo.regn = regn; ctx->dsi_cinfo.n = n;
ctx->dsi_cinfo.regm = regm; ctx->dsi_cinfo.m = m;
ctx->dsi_cinfo.fint = fint; ctx->dsi_cinfo.fint = fint;
ctx->dsi_cinfo.clkin4ddr = pll; ctx->dsi_cinfo.clkdco = clkdco;
return dsi_hsdiv_calc(ctx->dsidev, pll, ctx->pck_min, return dss_pll_hsdiv_calc(ctx->pll, clkdco,
dpi_calc_hsdiv_cb, ctx); ctx->pck_min, dss_feat_get_param_max(FEAT_PARAM_DSS_FCK),
dpi_calc_hsdiv_cb, ctx);
} }
static bool dpi_calc_dss_cb(unsigned long fck, void *data) static bool dpi_calc_dss_cb(unsigned long fck, void *data)
...@@ -200,23 +215,23 @@ static bool dpi_calc_dss_cb(unsigned long fck, void *data) ...@@ -200,23 +215,23 @@ static bool dpi_calc_dss_cb(unsigned long fck, void *data)
dpi_calc_dispc_cb, ctx); dpi_calc_dispc_cb, ctx);
} }
static bool dpi_dsi_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx) static bool dpi_dsi_clk_calc(struct dpi_data *dpi, unsigned long pck,
struct dpi_clk_calc_ctx *ctx)
{ {
unsigned long clkin; unsigned long clkin;
unsigned long pll_min, pll_max; unsigned long pll_min, pll_max;
clkin = dsi_get_pll_clkin(dpi.dsidev);
memset(ctx, 0, sizeof(*ctx)); memset(ctx, 0, sizeof(*ctx));
ctx->dsidev = dpi.dsidev; ctx->pll = dpi->pll;
ctx->pck_min = pck - 1000; ctx->pck_min = pck - 1000;
ctx->pck_max = pck + 1000; ctx->pck_max = pck + 1000;
ctx->dsi_cinfo.clkin = clkin;
pll_min = 0; pll_min = 0;
pll_max = 0; pll_max = 0;
return dsi_pll_calc(dpi.dsidev, clkin, clkin = clk_get_rate(ctx->pll->clkin);
return dss_pll_calc(ctx->pll, clkin,
pll_min, pll_max, pll_min, pll_max,
dpi_calc_pll_cb, ctx); dpi_calc_pll_cb, ctx);
} }
...@@ -252,7 +267,7 @@ static bool dpi_dss_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx) ...@@ -252,7 +267,7 @@ static bool dpi_dss_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx)
static int dpi_set_dsi_clk(enum omap_channel channel, static int dpi_set_dsi_clk(struct dpi_data *dpi, enum omap_channel channel,
unsigned long pck_req, unsigned long *fck, int *lck_div, unsigned long pck_req, unsigned long *fck, int *lck_div,
int *pck_div) int *pck_div)
{ {
...@@ -260,28 +275,28 @@ static int dpi_set_dsi_clk(enum omap_channel channel, ...@@ -260,28 +275,28 @@ static int dpi_set_dsi_clk(enum omap_channel channel,
int r; int r;
bool ok; bool ok;
ok = dpi_dsi_clk_calc(pck_req, &ctx); ok = dpi_dsi_clk_calc(dpi, pck_req, &ctx);
if (!ok) if (!ok)
return -EINVAL; return -EINVAL;
r = dsi_pll_set_clock_div(dpi.dsidev, &ctx.dsi_cinfo); r = dss_pll_set_config(dpi->pll, &ctx.dsi_cinfo);
if (r) if (r)
return r; return r;
dss_select_lcd_clk_source(channel, dss_select_lcd_clk_source(channel,
dpi_get_alt_clk_src(channel)); dpi_get_alt_clk_src(channel));
dpi.mgr_config.clock_info = ctx.dispc_cinfo; dpi->mgr_config.clock_info = ctx.dispc_cinfo;
*fck = ctx.dsi_cinfo.dsi_pll_hsdiv_dispc_clk; *fck = ctx.dsi_cinfo.clkout[HSDIV_DISPC];
*lck_div = ctx.dispc_cinfo.lck_div; *lck_div = ctx.dispc_cinfo.lck_div;
*pck_div = ctx.dispc_cinfo.pck_div; *pck_div = ctx.dispc_cinfo.pck_div;
return 0; return 0;
} }
static int dpi_set_dispc_clk(unsigned long pck_req, unsigned long *fck, static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req,
int *lck_div, int *pck_div) unsigned long *fck, int *lck_div, int *pck_div)
{ {
struct dpi_clk_calc_ctx ctx; struct dpi_clk_calc_ctx ctx;
int r; int r;
...@@ -295,7 +310,7 @@ static int dpi_set_dispc_clk(unsigned long pck_req, unsigned long *fck, ...@@ -295,7 +310,7 @@ static int dpi_set_dispc_clk(unsigned long pck_req, unsigned long *fck,
if (r) if (r)
return r; return r;
dpi.mgr_config.clock_info = ctx.dispc_cinfo; dpi->mgr_config.clock_info = ctx.dispc_cinfo;
*fck = ctx.fck; *fck = ctx.fck;
*lck_div = ctx.dispc_cinfo.lck_div; *lck_div = ctx.dispc_cinfo.lck_div;
...@@ -304,19 +319,21 @@ static int dpi_set_dispc_clk(unsigned long pck_req, unsigned long *fck, ...@@ -304,19 +319,21 @@ static int dpi_set_dispc_clk(unsigned long pck_req, unsigned long *fck,
return 0; return 0;
} }
static int dpi_set_mode(struct omap_overlay_manager *mgr) static int dpi_set_mode(struct dpi_data *dpi)
{ {
struct omap_video_timings *t = &dpi.timings; struct omap_dss_device *out = &dpi->output;
struct omap_overlay_manager *mgr = out->manager;
struct omap_video_timings *t = &dpi->timings;
int lck_div = 0, pck_div = 0; int lck_div = 0, pck_div = 0;
unsigned long fck = 0; unsigned long fck = 0;
unsigned long pck; unsigned long pck;
int r = 0; int r = 0;
if (dpi.dsidev) if (dpi->pll)
r = dpi_set_dsi_clk(mgr->id, t->pixelclock, &fck, r = dpi_set_dsi_clk(dpi, mgr->id, t->pixelclock, &fck,
&lck_div, &pck_div); &lck_div, &pck_div);
else else
r = dpi_set_dispc_clk(t->pixelclock, &fck, r = dpi_set_dispc_clk(dpi, t->pixelclock, &fck,
&lck_div, &pck_div); &lck_div, &pck_div);
if (r) if (r)
return r; return r;
...@@ -335,28 +352,32 @@ static int dpi_set_mode(struct omap_overlay_manager *mgr) ...@@ -335,28 +352,32 @@ static int dpi_set_mode(struct omap_overlay_manager *mgr)
return 0; return 0;
} }
static void dpi_config_lcd_manager(struct omap_overlay_manager *mgr) static void dpi_config_lcd_manager(struct dpi_data *dpi)
{ {
dpi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; struct omap_dss_device *out = &dpi->output;
struct omap_overlay_manager *mgr = out->manager;
dpi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
dpi.mgr_config.stallmode = false; dpi->mgr_config.stallmode = false;
dpi.mgr_config.fifohandcheck = false; dpi->mgr_config.fifohandcheck = false;
dpi.mgr_config.video_port_width = dpi.data_lines; dpi->mgr_config.video_port_width = dpi->data_lines;
dpi.mgr_config.lcden_sig_polarity = 0; dpi->mgr_config.lcden_sig_polarity = 0;
dss_mgr_set_lcd_config(mgr, &dpi.mgr_config); dss_mgr_set_lcd_config(mgr, &dpi->mgr_config);
} }
static int dpi_display_enable(struct omap_dss_device *dssdev) static int dpi_display_enable(struct omap_dss_device *dssdev)
{ {
struct omap_dss_device *out = &dpi.output; struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
struct omap_dss_device *out = &dpi->output;
int r; int r;
mutex_lock(&dpi.lock); mutex_lock(&dpi->lock);
if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && !dpi.vdds_dsi_reg) { if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && !dpi->vdds_dsi_reg) {
DSSERR("no VDSS_DSI regulator\n"); DSSERR("no VDSS_DSI regulator\n");
r = -ENODEV; r = -ENODEV;
goto err_no_reg; goto err_no_reg;
...@@ -369,7 +390,7 @@ static int dpi_display_enable(struct omap_dss_device *dssdev) ...@@ -369,7 +390,7 @@ static int dpi_display_enable(struct omap_dss_device *dssdev)
} }
if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) { if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) {
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;
} }
...@@ -378,25 +399,21 @@ static int dpi_display_enable(struct omap_dss_device *dssdev) ...@@ -378,25 +399,21 @@ static int dpi_display_enable(struct omap_dss_device *dssdev)
if (r) if (r)
goto err_get_dispc; goto err_get_dispc;
r = dss_dpi_select_source(out->manager->id); r = dss_dpi_select_source(out->port_num, out->manager->id);
if (r) if (r)
goto err_src_sel; goto err_src_sel;
if (dpi.dsidev) { if (dpi->pll) {
r = dsi_runtime_get(dpi.dsidev); r = dss_pll_enable(dpi->pll);
if (r)
goto err_get_dsi;
r = dsi_pll_init(dpi.dsidev, 0, 1);
if (r) if (r)
goto err_dsi_pll_init; goto err_dsi_pll_init;
} }
r = dpi_set_mode(out->manager); r = dpi_set_mode(dpi);
if (r) if (r)
goto err_set_mode; goto err_set_mode;
dpi_config_lcd_manager(out->manager); dpi_config_lcd_manager(dpi);
mdelay(2); mdelay(2);
...@@ -404,78 +421,80 @@ static int dpi_display_enable(struct omap_dss_device *dssdev) ...@@ -404,78 +421,80 @@ static int dpi_display_enable(struct omap_dss_device *dssdev)
if (r) if (r)
goto err_mgr_enable; goto err_mgr_enable;
mutex_unlock(&dpi.lock); mutex_unlock(&dpi->lock);
return 0; return 0;
err_mgr_enable: err_mgr_enable:
err_set_mode: err_set_mode:
if (dpi.dsidev) if (dpi->pll)
dsi_pll_uninit(dpi.dsidev, true); dss_pll_disable(dpi->pll);
err_dsi_pll_init: err_dsi_pll_init:
if (dpi.dsidev)
dsi_runtime_put(dpi.dsidev);
err_get_dsi:
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 (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
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: err_no_reg:
mutex_unlock(&dpi.lock); mutex_unlock(&dpi->lock);
return r; return r;
} }
static void dpi_display_disable(struct omap_dss_device *dssdev) static void dpi_display_disable(struct omap_dss_device *dssdev)
{ {
struct omap_overlay_manager *mgr = dpi.output.manager; struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
struct omap_overlay_manager *mgr = dpi->output.manager;
mutex_lock(&dpi.lock); mutex_lock(&dpi->lock);
dss_mgr_disable(mgr); dss_mgr_disable(mgr);
if (dpi.dsidev) { if (dpi->pll) {
dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK); dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
dsi_pll_uninit(dpi.dsidev, true); dss_pll_disable(dpi->pll);
dsi_runtime_put(dpi.dsidev);
} }
dispc_runtime_put(); dispc_runtime_put();
if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
regulator_disable(dpi.vdds_dsi_reg); regulator_disable(dpi->vdds_dsi_reg);
mutex_unlock(&dpi.lock); mutex_unlock(&dpi->lock);
} }
static void dpi_set_timings(struct omap_dss_device *dssdev, static void dpi_set_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings) struct omap_video_timings *timings)
{ {
struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
DSSDBG("dpi_set_timings\n"); DSSDBG("dpi_set_timings\n");
mutex_lock(&dpi.lock); mutex_lock(&dpi->lock);
dpi.timings = *timings; dpi->timings = *timings;
mutex_unlock(&dpi.lock); mutex_unlock(&dpi->lock);
} }
static void dpi_get_timings(struct omap_dss_device *dssdev, static void dpi_get_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings) struct omap_video_timings *timings)
{ {
mutex_lock(&dpi.lock); struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
mutex_lock(&dpi->lock);
*timings = dpi.timings; *timings = dpi->timings;
mutex_unlock(&dpi.lock); mutex_unlock(&dpi->lock);
} }
static int dpi_check_timings(struct omap_dss_device *dssdev, static int dpi_check_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings) struct omap_video_timings *timings)
{ {
struct omap_overlay_manager *mgr = dpi.output.manager; struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
struct omap_overlay_manager *mgr = dpi->output.manager;
int lck_div, pck_div; int lck_div, pck_div;
unsigned long fck; unsigned long fck;
unsigned long pck; unsigned long pck;
...@@ -488,12 +507,12 @@ static int dpi_check_timings(struct omap_dss_device *dssdev, ...@@ -488,12 +507,12 @@ static int dpi_check_timings(struct omap_dss_device *dssdev,
if (timings->pixelclock == 0) if (timings->pixelclock == 0)
return -EINVAL; return -EINVAL;
if (dpi.dsidev) { if (dpi->pll) {
ok = dpi_dsi_clk_calc(timings->pixelclock, &ctx); ok = dpi_dsi_clk_calc(dpi, timings->pixelclock, &ctx);
if (!ok) if (!ok)
return -EINVAL; return -EINVAL;
fck = ctx.dsi_cinfo.dsi_pll_hsdiv_dispc_clk; fck = ctx.dsi_cinfo.clkout[HSDIV_DISPC];
} else { } else {
ok = dpi_dss_clk_calc(timings->pixelclock, &ctx); ok = dpi_dss_clk_calc(timings->pixelclock, &ctx);
if (!ok) if (!ok)
...@@ -514,74 +533,69 @@ static int dpi_check_timings(struct omap_dss_device *dssdev, ...@@ -514,74 +533,69 @@ static int dpi_check_timings(struct omap_dss_device *dssdev,
static void dpi_set_data_lines(struct omap_dss_device *dssdev, int data_lines) static void dpi_set_data_lines(struct omap_dss_device *dssdev, int data_lines)
{ {
mutex_lock(&dpi.lock); struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
dpi.data_lines = data_lines; mutex_lock(&dpi->lock);
mutex_unlock(&dpi.lock); dpi->data_lines = data_lines;
mutex_unlock(&dpi->lock);
} }
static int dpi_verify_dsi_pll(struct platform_device *dsidev) static int dpi_verify_dsi_pll(struct dss_pll *pll)
{ {
int r; int r;
/* do initial setup with the PLL to see if it is operational */ /* do initial setup with the PLL to see if it is operational */
r = dsi_runtime_get(dsidev); r = dss_pll_enable(pll);
if (r) if (r)
return r; return r;
r = dsi_pll_init(dsidev, 0, 1); dss_pll_disable(pll);
if (r) {
dsi_runtime_put(dsidev);
return r;
}
dsi_pll_uninit(dsidev, true);
dsi_runtime_put(dsidev);
return 0; return 0;
} }
static int dpi_init_regulator(void) 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)) if (!dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
return 0; return 0;
if (dpi.vdds_dsi_reg) if (dpi->vdds_dsi_reg)
return 0; return 0;
vdds_dsi = devm_regulator_get(&dpi.pdev->dev, "vdds_dsi"); vdds_dsi = devm_regulator_get(&dpi->pdev->dev, "vdds_dsi");
if (IS_ERR(vdds_dsi)) { if (IS_ERR(vdds_dsi)) {
if (PTR_ERR(vdds_dsi) != -EPROBE_DEFER) if (PTR_ERR(vdds_dsi) != -EPROBE_DEFER)
DSSERR("can't get VDDS_DSI regulator\n"); DSSERR("can't get VDDS_DSI regulator\n");
return PTR_ERR(vdds_dsi); return PTR_ERR(vdds_dsi);
} }
dpi.vdds_dsi_reg = vdds_dsi; dpi->vdds_dsi_reg = vdds_dsi;
return 0; return 0;
} }
static void dpi_init_pll(void) static void dpi_init_pll(struct dpi_data *dpi)
{ {
struct platform_device *dsidev; struct dss_pll *pll;
if (dpi.dsidev) if (dpi->pll)
return; return;
dsidev = dpi_get_dsidev(dpi.output.dispc_channel); pll = dpi_get_pll(dpi->output.dispc_channel);
if (!dsidev) if (!pll)
return; return;
if (dpi_verify_dsi_pll(dsidev)) { if (dpi_verify_dsi_pll(pll)) {
DSSWARN("DSI PLL not operational\n"); DSSWARN("DSI PLL not operational\n");
return; return;
} }
dpi.dsidev = dsidev; dpi->pll = pll;
} }
/* /*
...@@ -590,7 +604,7 @@ static void dpi_init_pll(void) ...@@ -590,7 +604,7 @@ static void dpi_init_pll(void)
* 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(void) static enum omap_channel dpi_get_channel(int port_num)
{ {
switch (omapdss_get_version()) { switch (omapdss_get_version()) {
case OMAPDSS_VER_OMAP24xx: case OMAPDSS_VER_OMAP24xx:
...@@ -618,14 +632,15 @@ static enum omap_channel dpi_get_channel(void) ...@@ -618,14 +632,15 @@ static enum omap_channel dpi_get_channel(void)
static int dpi_connect(struct omap_dss_device *dssdev, static int dpi_connect(struct omap_dss_device *dssdev,
struct omap_dss_device *dst) struct omap_dss_device *dst)
{ {
struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
struct omap_overlay_manager *mgr; struct omap_overlay_manager *mgr;
int r; int r;
r = dpi_init_regulator(); r = dpi_init_regulator(dpi);
if (r) if (r)
return r; return r;
dpi_init_pll(); dpi_init_pll(dpi);
mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel); mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
if (!mgr) if (!mgr)
...@@ -676,13 +691,14 @@ static const struct omapdss_dpi_ops dpi_ops = { ...@@ -676,13 +691,14 @@ static const struct omapdss_dpi_ops dpi_ops = {
static void dpi_init_output(struct platform_device *pdev) static void dpi_init_output(struct platform_device *pdev)
{ {
struct omap_dss_device *out = &dpi.output; struct dpi_data *dpi = dpi_get_data_from_pdev(pdev);
struct omap_dss_device *out = &dpi->output;
out->dev = &pdev->dev; out->dev = &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->name = "dpi.0"; out->name = "dpi.0";
out->dispc_channel = dpi_get_channel(); out->dispc_channel = dpi_get_channel(0);
out->ops.dpi = &dpi_ops; out->ops.dpi = &dpi_ops;
out->owner = THIS_MODULE; out->owner = THIS_MODULE;
...@@ -691,16 +707,69 @@ static void dpi_init_output(struct platform_device *pdev) ...@@ -691,16 +707,69 @@ static void dpi_init_output(struct platform_device *pdev)
static void __exit dpi_uninit_output(struct platform_device *pdev) static void __exit dpi_uninit_output(struct platform_device *pdev)
{ {
struct omap_dss_device *out = &dpi.output; struct dpi_data *dpi = dpi_get_data_from_pdev(pdev);
struct omap_dss_device *out = &dpi->output;
omapdss_unregister_output(out);
}
static void dpi_init_output_port(struct platform_device *pdev,
struct device_node *port)
{
struct dpi_data *dpi = port->data;
struct omap_dss_device *out = &dpi->output;
int r;
u32 port_num;
r = of_property_read_u32(port, "reg", &port_num);
if (r)
port_num = 0;
switch (port_num) {
case 2:
out->name = "dpi.2";
break;
case 1:
out->name = "dpi.1";
break;
case 0:
default:
out->name = "dpi.0";
break;
}
out->dev = &pdev->dev;
out->id = OMAP_DSS_OUTPUT_DPI;
out->output_type = OMAP_DISPLAY_TYPE_DPI;
out->dispc_channel = dpi_get_channel(port_num);
out->port_num = port_num;
out->ops.dpi = &dpi_ops;
out->owner = THIS_MODULE;
omapdss_register_output(out);
}
static void __exit dpi_uninit_output_port(struct device_node *port)
{
struct dpi_data *dpi = port->data;
struct omap_dss_device *out = &dpi->output;
omapdss_unregister_output(out); omapdss_unregister_output(out);
} }
static int omap_dpi_probe(struct platform_device *pdev) static int omap_dpi_probe(struct platform_device *pdev)
{ {
dpi.pdev = pdev; struct dpi_data *dpi;
dpi = devm_kzalloc(&pdev->dev, sizeof(*dpi), GFP_KERNEL);
if (!dpi)
return -ENOMEM;
mutex_init(&dpi.lock); dpi->pdev = pdev;
dev_set_drvdata(&pdev->dev, dpi);
mutex_init(&dpi->lock);
dpi_init_output(pdev); dpi_init_output(pdev);
...@@ -736,10 +805,15 @@ void __exit dpi_uninit_platform_driver(void) ...@@ -736,10 +805,15 @@ void __exit dpi_uninit_platform_driver(void)
int __init dpi_init_port(struct platform_device *pdev, struct device_node *port) int __init dpi_init_port(struct platform_device *pdev, struct device_node *port)
{ {
struct dpi_data *dpi;
struct device_node *ep; struct device_node *ep;
u32 datalines; u32 datalines;
int r; int r;
dpi = devm_kzalloc(&pdev->dev, sizeof(*dpi), GFP_KERNEL);
if (!dpi)
return -ENOMEM;
ep = omapdss_of_get_next_endpoint(port, NULL); ep = omapdss_of_get_next_endpoint(port, NULL);
if (!ep) if (!ep)
return 0; return 0;
...@@ -750,17 +824,18 @@ int __init dpi_init_port(struct platform_device *pdev, struct device_node *port) ...@@ -750,17 +824,18 @@ int __init dpi_init_port(struct platform_device *pdev, struct device_node *port)
goto err_datalines; goto err_datalines;
} }
dpi.data_lines = datalines; dpi->data_lines = datalines;
of_node_put(ep); of_node_put(ep);
dpi.pdev = pdev; dpi->pdev = pdev;
port->data = dpi;
mutex_init(&dpi.lock); mutex_init(&dpi->lock);
dpi_init_output(pdev); dpi_init_output_port(pdev, port);
dpi.port_initialized = true; dpi->port_initialized = true;
return 0; return 0;
...@@ -770,10 +845,12 @@ int __init dpi_init_port(struct platform_device *pdev, struct device_node *port) ...@@ -770,10 +845,12 @@ int __init dpi_init_port(struct platform_device *pdev, struct device_node *port)
return r; return r;
} }
void __exit dpi_uninit_port(void) void __exit dpi_uninit_port(struct device_node *port)
{ {
if (!dpi.port_initialized) struct dpi_data *dpi = port->data;
if (!dpi->port_initialized)
return; return;
dpi_uninit_output(dpi.pdev); dpi_uninit_output_port(port);
} }
此差异已折叠。
...@@ -20,6 +20,8 @@ ...@@ -20,6 +20,8 @@
#include <video/omapdss.h> #include <video/omapdss.h>
#include "dss.h"
struct device_node * struct device_node *
omapdss_of_get_next_port(const struct device_node *parent, omapdss_of_get_next_port(const struct device_node *parent,
struct device_node *prev) struct device_node *prev)
...@@ -84,20 +86,17 @@ omapdss_of_get_next_endpoint(const struct device_node *parent, ...@@ -84,20 +86,17 @@ omapdss_of_get_next_endpoint(const struct device_node *parent,
} }
EXPORT_SYMBOL_GPL(omapdss_of_get_next_endpoint); EXPORT_SYMBOL_GPL(omapdss_of_get_next_endpoint);
static struct device_node * struct device_node *dss_of_port_get_parent_device(struct device_node *port)
omapdss_of_get_remote_device_node(const struct device_node *node)
{ {
struct device_node *np; struct device_node *np;
int i; int i;
np = of_parse_phandle(node, "remote-endpoint", 0); if (!port)
if (!np)
return NULL; return NULL;
np = of_get_next_parent(np); np = of_get_next_parent(port);
for (i = 0; i < 3 && np; ++i) { for (i = 0; i < 2 && np; ++i) {
struct property *prop; struct property *prop;
prop = of_find_property(np, "compatible", NULL); prop = of_find_property(np, "compatible", NULL);
...@@ -111,6 +110,31 @@ omapdss_of_get_remote_device_node(const struct device_node *node) ...@@ -111,6 +110,31 @@ omapdss_of_get_remote_device_node(const struct device_node *node)
return NULL; return NULL;
} }
u32 dss_of_port_get_port_number(struct device_node *port)
{
int r;
u32 reg;
r = of_property_read_u32(port, "reg", &reg);
if (r)
reg = 0;
return reg;
}
static struct device_node *omapdss_of_get_remote_port(const struct device_node *node)
{
struct device_node *np;
np = of_parse_phandle(node, "remote-endpoint", 0);
if (!np)
return NULL;
np = of_get_next_parent(np);
return np;
}
struct device_node * struct device_node *
omapdss_of_get_first_endpoint(const struct device_node *parent) omapdss_of_get_first_endpoint(const struct device_node *parent)
{ {
...@@ -133,27 +157,25 @@ struct omap_dss_device * ...@@ -133,27 +157,25 @@ struct omap_dss_device *
omapdss_of_find_source_for_first_ep(struct device_node *node) omapdss_of_find_source_for_first_ep(struct device_node *node)
{ {
struct device_node *ep; struct device_node *ep;
struct device_node *src_node; struct device_node *src_port;
struct omap_dss_device *src; struct omap_dss_device *src;
ep = omapdss_of_get_first_endpoint(node); ep = omapdss_of_get_first_endpoint(node);
if (!ep) if (!ep)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
src_node = omapdss_of_get_remote_device_node(ep); src_port = omapdss_of_get_remote_port(ep);
if (!src_port) {
of_node_put(ep); of_node_put(ep);
if (!src_node)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
}
src = omap_dss_find_output_by_node(src_node); of_node_put(ep);
of_node_put(src_node); src = omap_dss_find_output_by_port_node(src_port);
if (!src) of_node_put(src_port);
return ERR_PTR(-EPROBE_DEFER);
return src; return src ? src : ERR_PTR(-EPROBE_DEFER);
} }
EXPORT_SYMBOL_GPL(omapdss_of_find_source_for_first_ep); EXPORT_SYMBOL_GPL(omapdss_of_find_source_for_first_ep);
...@@ -70,7 +70,9 @@ struct dss_features { ...@@ -70,7 +70,9 @@ struct dss_features {
u8 fck_div_max; u8 fck_div_max;
u8 dss_fck_multiplier; u8 dss_fck_multiplier;
const char *parent_clk_name; const char *parent_clk_name;
int (*dpi_select_source)(enum omap_channel channel); enum omap_display_type *ports;
int num_ports;
int (*dpi_select_source)(int port, enum omap_channel channel);
}; };
static struct { static struct {
...@@ -294,7 +296,6 @@ static void dss_dump_regs(struct seq_file *s) ...@@ -294,7 +296,6 @@ static void dss_dump_regs(struct seq_file *s)
static void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src) static void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src)
{ {
struct platform_device *dsidev;
int b; int b;
u8 start, end; u8 start, end;
...@@ -304,13 +305,9 @@ static void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src) ...@@ -304,13 +305,9 @@ static void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src)
break; break;
case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
b = 1; b = 1;
dsidev = dsi_get_dsidev_from_id(0);
dsi_wait_pll_hsdiv_dispc_active(dsidev);
break; break;
case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC: case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
b = 2; b = 2;
dsidev = dsi_get_dsidev_from_id(1);
dsi_wait_pll_hsdiv_dispc_active(dsidev);
break; break;
default: default:
BUG(); BUG();
...@@ -327,7 +324,6 @@ static void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src) ...@@ -327,7 +324,6 @@ static void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src)
void dss_select_dsi_clk_source(int dsi_module, void dss_select_dsi_clk_source(int dsi_module,
enum omap_dss_clk_source clk_src) enum omap_dss_clk_source clk_src)
{ {
struct platform_device *dsidev;
int b, pos; int b, pos;
switch (clk_src) { switch (clk_src) {
...@@ -337,14 +333,10 @@ void dss_select_dsi_clk_source(int dsi_module, ...@@ -337,14 +333,10 @@ void dss_select_dsi_clk_source(int dsi_module,
case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI: case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI:
BUG_ON(dsi_module != 0); BUG_ON(dsi_module != 0);
b = 1; b = 1;
dsidev = dsi_get_dsidev_from_id(0);
dsi_wait_pll_hsdiv_dsi_active(dsidev);
break; break;
case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI: case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI:
BUG_ON(dsi_module != 1); BUG_ON(dsi_module != 1);
b = 1; b = 1;
dsidev = dsi_get_dsidev_from_id(1);
dsi_wait_pll_hsdiv_dsi_active(dsidev);
break; break;
default: default:
BUG(); BUG();
...@@ -360,7 +352,6 @@ void dss_select_dsi_clk_source(int dsi_module, ...@@ -360,7 +352,6 @@ void dss_select_dsi_clk_source(int dsi_module,
void dss_select_lcd_clk_source(enum omap_channel channel, void dss_select_lcd_clk_source(enum omap_channel channel,
enum omap_dss_clk_source clk_src) enum omap_dss_clk_source clk_src)
{ {
struct platform_device *dsidev;
int b, ix, pos; int b, ix, pos;
if (!dss_has_feature(FEAT_LCD_CLK_SRC)) { if (!dss_has_feature(FEAT_LCD_CLK_SRC)) {
...@@ -375,15 +366,11 @@ void dss_select_lcd_clk_source(enum omap_channel channel, ...@@ -375,15 +366,11 @@ void dss_select_lcd_clk_source(enum omap_channel channel,
case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
BUG_ON(channel != OMAP_DSS_CHANNEL_LCD); BUG_ON(channel != OMAP_DSS_CHANNEL_LCD);
b = 1; b = 1;
dsidev = dsi_get_dsidev_from_id(0);
dsi_wait_pll_hsdiv_dispc_active(dsidev);
break; break;
case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC: case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
BUG_ON(channel != OMAP_DSS_CHANNEL_LCD2 && BUG_ON(channel != OMAP_DSS_CHANNEL_LCD2 &&
channel != OMAP_DSS_CHANNEL_LCD3); channel != OMAP_DSS_CHANNEL_LCD3);
b = 1; b = 1;
dsidev = dsi_get_dsidev_from_id(1);
dsi_wait_pll_hsdiv_dispc_active(dsidev);
break; break;
default: default:
BUG(); BUG();
...@@ -564,7 +551,7 @@ enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void) ...@@ -564,7 +551,7 @@ enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void)
return REG_GET(DSS_CONTROL, 15, 15); return REG_GET(DSS_CONTROL, 15, 15);
} }
static int dss_dpi_select_source_omap2_omap3(enum omap_channel channel) static int dss_dpi_select_source_omap2_omap3(int port, enum omap_channel channel)
{ {
if (channel != OMAP_DSS_CHANNEL_LCD) if (channel != OMAP_DSS_CHANNEL_LCD)
return -EINVAL; return -EINVAL;
...@@ -572,7 +559,7 @@ static int dss_dpi_select_source_omap2_omap3(enum omap_channel channel) ...@@ -572,7 +559,7 @@ static int dss_dpi_select_source_omap2_omap3(enum omap_channel channel)
return 0; return 0;
} }
static int dss_dpi_select_source_omap4(enum omap_channel channel) static int dss_dpi_select_source_omap4(int port, enum omap_channel channel)
{ {
int val; int val;
...@@ -592,7 +579,7 @@ static int dss_dpi_select_source_omap4(enum omap_channel channel) ...@@ -592,7 +579,7 @@ static int dss_dpi_select_source_omap4(enum omap_channel channel)
return 0; return 0;
} }
static int dss_dpi_select_source_omap5(enum omap_channel channel) static int dss_dpi_select_source_omap5(int port, enum omap_channel channel)
{ {
int val; int val;
...@@ -618,9 +605,9 @@ static int dss_dpi_select_source_omap5(enum omap_channel channel) ...@@ -618,9 +605,9 @@ static int dss_dpi_select_source_omap5(enum omap_channel channel)
return 0; return 0;
} }
int dss_dpi_select_source(enum omap_channel channel) int dss_dpi_select_source(int port, enum omap_channel channel)
{ {
return dss.feat->dpi_select_source(channel); return dss.feat->dpi_select_source(port, channel);
} }
static int dss_get_clocks(void) static int dss_get_clocks(void)
...@@ -689,6 +676,16 @@ void dss_debug_dump_clocks(struct seq_file *s) ...@@ -689,6 +676,16 @@ void dss_debug_dump_clocks(struct seq_file *s)
} }
#endif #endif
static enum omap_display_type omap2plus_ports[] = {
OMAP_DISPLAY_TYPE_DPI,
};
static enum omap_display_type omap34xx_ports[] = {
OMAP_DISPLAY_TYPE_DPI,
OMAP_DISPLAY_TYPE_SDI,
};
static const struct dss_features omap24xx_dss_feats __initconst = { static const struct dss_features omap24xx_dss_feats __initconst = {
/* /*
* 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
...@@ -698,6 +695,8 @@ static const struct dss_features omap24xx_dss_feats __initconst = { ...@@ -698,6 +695,8 @@ static const struct dss_features omap24xx_dss_feats __initconst = {
.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, .dpi_select_source = &dss_dpi_select_source_omap2_omap3,
.ports = omap2plus_ports,
.num_ports = ARRAY_SIZE(omap2plus_ports),
}; };
static const struct dss_features omap34xx_dss_feats __initconst = { static const struct dss_features omap34xx_dss_feats __initconst = {
...@@ -705,6 +704,8 @@ static const struct dss_features omap34xx_dss_feats __initconst = { ...@@ -705,6 +704,8 @@ static const struct dss_features omap34xx_dss_feats __initconst = {
.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, .dpi_select_source = &dss_dpi_select_source_omap2_omap3,
.ports = omap34xx_ports,
.num_ports = ARRAY_SIZE(omap34xx_ports),
}; };
static const struct dss_features omap3630_dss_feats __initconst = { static const struct dss_features omap3630_dss_feats __initconst = {
...@@ -712,6 +713,8 @@ static const struct dss_features omap3630_dss_feats __initconst = { ...@@ -712,6 +713,8 @@ static const struct dss_features omap3630_dss_feats __initconst = {
.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, .dpi_select_source = &dss_dpi_select_source_omap2_omap3,
.ports = omap2plus_ports,
.num_ports = ARRAY_SIZE(omap2plus_ports),
}; };
static const struct dss_features omap44xx_dss_feats __initconst = { static const struct dss_features omap44xx_dss_feats __initconst = {
...@@ -719,6 +722,8 @@ static const struct dss_features omap44xx_dss_feats __initconst = { ...@@ -719,6 +722,8 @@ static const struct dss_features omap44xx_dss_feats __initconst = {
.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, .dpi_select_source = &dss_dpi_select_source_omap4,
.ports = omap2plus_ports,
.num_ports = ARRAY_SIZE(omap2plus_ports),
}; };
static const struct dss_features omap54xx_dss_feats __initconst = { static const struct dss_features omap54xx_dss_feats __initconst = {
...@@ -726,6 +731,8 @@ static const struct dss_features omap54xx_dss_feats __initconst = { ...@@ -726,6 +731,8 @@ static const struct dss_features omap54xx_dss_feats __initconst = {
.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, .dpi_select_source = &dss_dpi_select_source_omap5,
.ports = omap2plus_ports,
.num_ports = ARRAY_SIZE(omap2plus_ports),
}; };
static const struct dss_features am43xx_dss_feats __initconst = { static const struct dss_features am43xx_dss_feats __initconst = {
...@@ -733,6 +740,8 @@ static const struct dss_features am43xx_dss_feats __initconst = { ...@@ -733,6 +740,8 @@ static const struct dss_features am43xx_dss_feats __initconst = {
.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, .dpi_select_source = &dss_dpi_select_source_omap2_omap3,
.ports = omap2plus_ports,
.num_ports = ARRAY_SIZE(omap2plus_ports),
}; };
static int __init dss_init_features(struct platform_device *pdev) static int __init dss_init_features(struct platform_device *pdev)
...@@ -798,37 +807,77 @@ static int __init dss_init_ports(struct platform_device *pdev) ...@@ -798,37 +807,77 @@ static int __init dss_init_ports(struct platform_device *pdev)
if (!port) if (!port)
return 0; return 0;
if (dss.feat->num_ports == 0)
return 0;
do { do {
enum omap_display_type port_type;
u32 reg; u32 reg;
r = of_property_read_u32(port, "reg", &reg); r = of_property_read_u32(port, "reg", &reg);
if (r) if (r)
reg = 0; reg = 0;
#ifdef CONFIG_OMAP2_DSS_DPI if (reg >= dss.feat->num_ports)
if (reg == 0) continue;
dpi_init_port(pdev, port);
#endif
#ifdef CONFIG_OMAP2_DSS_SDI port_type = dss.feat->ports[reg];
if (reg == 1)
sdi_init_port(pdev, port);
#endif
switch (port_type) {
case OMAP_DISPLAY_TYPE_DPI:
dpi_init_port(pdev, port);
break;
case OMAP_DISPLAY_TYPE_SDI:
sdi_init_port(pdev, port);
break;
default:
break;
}
} while ((port = omapdss_of_get_next_port(parent, port)) != NULL); } while ((port = omapdss_of_get_next_port(parent, port)) != NULL);
return 0; return 0;
} }
static void __exit dss_uninit_ports(void) static void __exit dss_uninit_ports(struct platform_device *pdev)
{ {
#ifdef CONFIG_OMAP2_DSS_DPI struct device_node *parent = pdev->dev.of_node;
dpi_uninit_port(); struct device_node *port;
#endif
#ifdef CONFIG_OMAP2_DSS_SDI if (parent == NULL)
sdi_uninit_port(); return;
#endif
port = omapdss_of_get_next_port(parent, NULL);
if (!port)
return;
if (dss.feat->num_ports == 0)
return;
do {
enum omap_display_type port_type;
u32 reg;
int r;
r = of_property_read_u32(port, "reg", &reg);
if (r)
reg = 0;
if (reg >= dss.feat->num_ports)
continue;
port_type = dss.feat->ports[reg];
switch (port_type) {
case OMAP_DISPLAY_TYPE_DPI:
dpi_uninit_port(port);
break;
case OMAP_DISPLAY_TYPE_SDI:
sdi_uninit_port(port);
break;
default:
break;
}
} while ((port = omapdss_of_get_next_port(parent, port)) != NULL);
} }
/* DSS HW IP initialisation */ /* DSS HW IP initialisation */
...@@ -910,7 +959,7 @@ static int __init omap_dsshw_probe(struct platform_device *pdev) ...@@ -910,7 +959,7 @@ static int __init omap_dsshw_probe(struct platform_device *pdev)
static int __exit omap_dsshw_remove(struct platform_device *pdev) static int __exit omap_dsshw_remove(struct platform_device *pdev)
{ {
dss_uninit_ports(); dss_uninit_ports(pdev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
......
...@@ -100,35 +100,77 @@ enum dss_writeback_channel { ...@@ -100,35 +100,77 @@ enum dss_writeback_channel {
DSS_WB_LCD3_MGR = 7, DSS_WB_LCD3_MGR = 7,
}; };
struct dispc_clock_info { struct dss_pll;
#define DSS_PLL_MAX_HSDIVS 4
/*
* Type-A PLLs: clkout[]/mX[] refer to hsdiv outputs m4, m5, m6, m7.
* Type-B PLLs: clkout[0] refers to m2.
*/
struct dss_pll_clock_info {
/* rates that we get with dividers below */ /* rates that we get with dividers below */
unsigned long lck; unsigned long fint;
unsigned long pck; unsigned long clkdco;
unsigned long clkout[DSS_PLL_MAX_HSDIVS];
/* dividers */ /* dividers */
u16 lck_div; u16 n;
u16 pck_div; u16 m;
u32 mf;
u16 mX[DSS_PLL_MAX_HSDIVS];
u16 sd;
};
struct dss_pll_ops {
int (*enable)(struct dss_pll *pll);
void (*disable)(struct dss_pll *pll);
int (*set_config)(struct dss_pll *pll,
const struct dss_pll_clock_info *cinfo);
};
struct dss_pll_hw {
unsigned n_max;
unsigned m_min;
unsigned m_max;
unsigned mX_max;
unsigned long fint_min, fint_max;
unsigned long clkdco_min, clkdco_low, clkdco_max;
u8 n_msb, n_lsb;
u8 m_msb, m_lsb;
u8 mX_msb[DSS_PLL_MAX_HSDIVS], mX_lsb[DSS_PLL_MAX_HSDIVS];
bool has_stopmode;
bool has_freqsel;
bool has_selfreqdco;
bool has_refsel;
}; };
struct dsi_clock_info { struct dss_pll {
const char *name;
struct clk *clkin;
struct regulator *regulator;
void __iomem *base;
const struct dss_pll_hw *hw;
const struct dss_pll_ops *ops;
struct dss_pll_clock_info cinfo;
};
struct dispc_clock_info {
/* rates that we get with dividers below */ /* rates that we get with dividers below */
unsigned long fint; unsigned long lck;
unsigned long clkin4ddr; unsigned long pck;
unsigned long clkin;
unsigned long dsi_pll_hsdiv_dispc_clk; /* OMAP3: DSI1_PLL_CLK
* OMAP4: PLLx_CLK1 */
unsigned long dsi_pll_hsdiv_dsi_clk; /* OMAP3: DSI2_PLL_CLK
* OMAP4: PLLx_CLK2 */
unsigned long lp_clk;
/* dividers */ /* dividers */
u16 regn; u16 lck_div;
u16 regm; u16 pck_div;
u16 regm_dispc; /* OMAP3: REGM3
* OMAP4: REGM4 */
u16 regm_dsi; /* OMAP3: REGM4
* OMAP4: REGM5 */
u16 lp_clk_div;
}; };
struct dss_lcd_mgr_config { struct dss_lcd_mgr_config {
...@@ -209,12 +251,16 @@ int dss_init_platform_driver(void) __init; ...@@ -209,12 +251,16 @@ int dss_init_platform_driver(void) __init;
void dss_uninit_platform_driver(void); void dss_uninit_platform_driver(void);
unsigned long dss_get_dispc_clk_rate(void); unsigned long dss_get_dispc_clk_rate(void);
int dss_dpi_select_source(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);
const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src); const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src);
void dss_dump_clocks(struct seq_file *s); void dss_dump_clocks(struct seq_file *s);
/* dss-of */
struct device_node *dss_of_port_get_parent_device(struct device_node *port);
u32 dss_of_port_get_port_number(struct device_node *port);
#if defined(CONFIG_OMAP2_DSS_DEBUGFS) #if defined(CONFIG_OMAP2_DSS_DEBUGFS)
void dss_debug_dump_clocks(struct seq_file *s); void dss_debug_dump_clocks(struct seq_file *s);
#endif #endif
...@@ -244,16 +290,22 @@ bool dss_div_calc(unsigned long pck, unsigned long fck_min, ...@@ -244,16 +290,22 @@ bool dss_div_calc(unsigned long pck, unsigned long fck_min,
int sdi_init_platform_driver(void) __init; int sdi_init_platform_driver(void) __init;
void sdi_uninit_platform_driver(void) __exit; void sdi_uninit_platform_driver(void) __exit;
#ifdef CONFIG_OMAP2_DSS_SDI
int sdi_init_port(struct platform_device *pdev, struct device_node *port) __init; int sdi_init_port(struct platform_device *pdev, struct device_node *port) __init;
void sdi_uninit_port(void) __exit; void sdi_uninit_port(struct device_node *port) __exit;
#else
static inline int __init sdi_init_port(struct platform_device *pdev,
struct device_node *port)
{
return 0;
}
static inline void __exit sdi_uninit_port(struct device_node *port)
{
}
#endif
/* DSI */ /* DSI */
typedef bool (*dsi_pll_calc_func)(int regn, int regm, unsigned long fint,
unsigned long pll, void *data);
typedef bool (*dsi_hsdiv_calc_func)(int regm_dispc, unsigned long dispc,
void *data);
#ifdef CONFIG_OMAP2_DSS_DSI #ifdef CONFIG_OMAP2_DSS_DSI
struct dentry; struct dentry;
...@@ -262,104 +314,36 @@ struct file_operations; ...@@ -262,104 +314,36 @@ struct file_operations;
int dsi_init_platform_driver(void) __init; int dsi_init_platform_driver(void) __init;
void dsi_uninit_platform_driver(void) __exit; void dsi_uninit_platform_driver(void) __exit;
int dsi_runtime_get(struct platform_device *dsidev);
void dsi_runtime_put(struct platform_device *dsidev);
void dsi_dump_clocks(struct seq_file *s); void dsi_dump_clocks(struct seq_file *s);
void dsi_irq_handler(void); void dsi_irq_handler(void);
u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt); u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt);
unsigned long dsi_get_pll_clkin(struct platform_device *dsidev);
bool dsi_hsdiv_calc(struct platform_device *dsidev, unsigned long pll,
unsigned long out_min, dsi_hsdiv_calc_func func, void *data);
bool dsi_pll_calc(struct platform_device *dsidev, unsigned long clkin,
unsigned long pll_min, unsigned long pll_max,
dsi_pll_calc_func func, void *data);
unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev);
int dsi_pll_set_clock_div(struct platform_device *dsidev,
struct dsi_clock_info *cinfo);
int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk,
bool enable_hsdiv);
void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes);
void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev);
void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev);
struct platform_device *dsi_get_dsidev_from_id(int module);
#else #else
static inline int dsi_runtime_get(struct platform_device *dsidev)
{
return 0;
}
static inline void dsi_runtime_put(struct platform_device *dsidev)
{
}
static inline u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt) static inline u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt)
{ {
WARN("%s: DSI not compiled in, returning pixel_size as 0\n", __func__); WARN("%s: DSI not compiled in, returning pixel_size as 0\n", __func__);
return 0; return 0;
} }
static inline unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev)
{
WARN("%s: DSI not compiled in, returning rate as 0\n", __func__);
return 0;
}
static inline int dsi_pll_set_clock_div(struct platform_device *dsidev,
struct dsi_clock_info *cinfo)
{
WARN("%s: DSI not compiled in\n", __func__);
return -ENODEV;
}
static inline int dsi_pll_init(struct platform_device *dsidev,
bool enable_hsclk, bool enable_hsdiv)
{
WARN("%s: DSI not compiled in\n", __func__);
return -ENODEV;
}
static inline void dsi_pll_uninit(struct platform_device *dsidev,
bool disconnect_lanes)
{
}
static inline void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev)
{
}
static inline void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev)
{
}
static inline struct platform_device *dsi_get_dsidev_from_id(int module)
{
return NULL;
}
static inline unsigned long dsi_get_pll_clkin(struct platform_device *dsidev)
{
return 0;
}
static inline bool dsi_hsdiv_calc(struct platform_device *dsidev,
unsigned long pll, unsigned long out_min,
dsi_hsdiv_calc_func func, void *data)
{
return false;
}
static inline bool dsi_pll_calc(struct platform_device *dsidev,
unsigned long clkin,
unsigned long pll_min, unsigned long pll_max,
dsi_pll_calc_func func, void *data)
{
return false;
}
#endif #endif
/* DPI */ /* DPI */
int dpi_init_platform_driver(void) __init; int dpi_init_platform_driver(void) __init;
void dpi_uninit_platform_driver(void) __exit; void dpi_uninit_platform_driver(void) __exit;
#ifdef CONFIG_OMAP2_DSS_DPI
int dpi_init_port(struct platform_device *pdev, struct device_node *port) __init; int dpi_init_port(struct platform_device *pdev, struct device_node *port) __init;
void dpi_uninit_port(void) __exit; void dpi_uninit_port(struct device_node *port) __exit;
#else
static inline int __init dpi_init_port(struct platform_device *pdev,
struct device_node *port)
{
return 0;
}
static inline void __exit dpi_uninit_port(struct device_node *port)
{
}
#endif
/* DISPC */ /* DISPC */
int dispc_init_platform_driver(void) __init; int dispc_init_platform_driver(void) __init;
...@@ -438,4 +422,29 @@ static inline void dss_collect_irq_stats(u32 irqstatus, unsigned *irq_arr) ...@@ -438,4 +422,29 @@ static inline void dss_collect_irq_stats(u32 irqstatus, unsigned *irq_arr)
} }
#endif #endif
/* PLL */
typedef bool (*dss_pll_calc_func)(int n, int m, unsigned long fint,
unsigned long clkdco, void *data);
typedef bool (*dss_hsdiv_calc_func)(int m_dispc, unsigned long dispc,
void *data);
int dss_pll_register(struct dss_pll *pll);
void dss_pll_unregister(struct dss_pll *pll);
struct dss_pll *dss_pll_find(const char *name);
int dss_pll_enable(struct dss_pll *pll);
void dss_pll_disable(struct dss_pll *pll);
int dss_pll_set_config(struct dss_pll *pll,
const struct dss_pll_clock_info *cinfo);
bool dss_pll_hsdiv_calc(const struct dss_pll *pll, unsigned long clkdco,
unsigned long out_min, unsigned long out_max,
dss_hsdiv_calc_func func, void *data);
bool dss_pll_calc(const struct dss_pll *pll, unsigned long clkin,
unsigned long pll_min, unsigned long pll_max,
dss_pll_calc_func func, void *data);
int dss_pll_write_config_type_a(struct dss_pll *pll,
const struct dss_pll_clock_info *cinfo);
int dss_pll_write_config_type_b(struct dss_pll *pll,
const struct dss_pll_clock_info *cinfo);
#endif #endif
...@@ -72,10 +72,6 @@ static const struct dss_reg_field omap2_dss_reg_fields[] = { ...@@ -72,10 +72,6 @@ static const struct dss_reg_field omap2_dss_reg_fields[] = {
[FEAT_REG_HORIZONTALACCU] = { 9, 0 }, [FEAT_REG_HORIZONTALACCU] = { 9, 0 },
[FEAT_REG_VERTICALACCU] = { 25, 16 }, [FEAT_REG_VERTICALACCU] = { 25, 16 },
[FEAT_REG_DISPC_CLK_SWITCH] = { 0, 0 }, [FEAT_REG_DISPC_CLK_SWITCH] = { 0, 0 },
[FEAT_REG_DSIPLL_REGN] = { 0, 0 },
[FEAT_REG_DSIPLL_REGM] = { 0, 0 },
[FEAT_REG_DSIPLL_REGM_DISPC] = { 0, 0 },
[FEAT_REG_DSIPLL_REGM_DSI] = { 0, 0 },
}; };
static const struct dss_reg_field omap3_dss_reg_fields[] = { static const struct dss_reg_field omap3_dss_reg_fields[] = {
...@@ -87,10 +83,6 @@ static const struct dss_reg_field omap3_dss_reg_fields[] = { ...@@ -87,10 +83,6 @@ static const struct dss_reg_field omap3_dss_reg_fields[] = {
[FEAT_REG_HORIZONTALACCU] = { 9, 0 }, [FEAT_REG_HORIZONTALACCU] = { 9, 0 },
[FEAT_REG_VERTICALACCU] = { 25, 16 }, [FEAT_REG_VERTICALACCU] = { 25, 16 },
[FEAT_REG_DISPC_CLK_SWITCH] = { 0, 0 }, [FEAT_REG_DISPC_CLK_SWITCH] = { 0, 0 },
[FEAT_REG_DSIPLL_REGN] = { 7, 1 },
[FEAT_REG_DSIPLL_REGM] = { 18, 8 },
[FEAT_REG_DSIPLL_REGM_DISPC] = { 22, 19 },
[FEAT_REG_DSIPLL_REGM_DSI] = { 26, 23 },
}; };
static const struct dss_reg_field am43xx_dss_reg_fields[] = { static const struct dss_reg_field am43xx_dss_reg_fields[] = {
...@@ -113,10 +105,6 @@ static const struct dss_reg_field omap4_dss_reg_fields[] = { ...@@ -113,10 +105,6 @@ static const struct dss_reg_field omap4_dss_reg_fields[] = {
[FEAT_REG_HORIZONTALACCU] = { 10, 0 }, [FEAT_REG_HORIZONTALACCU] = { 10, 0 },
[FEAT_REG_VERTICALACCU] = { 26, 16 }, [FEAT_REG_VERTICALACCU] = { 26, 16 },
[FEAT_REG_DISPC_CLK_SWITCH] = { 9, 8 }, [FEAT_REG_DISPC_CLK_SWITCH] = { 9, 8 },
[FEAT_REG_DSIPLL_REGN] = { 8, 1 },
[FEAT_REG_DSIPLL_REGM] = { 20, 9 },
[FEAT_REG_DSIPLL_REGM_DISPC] = { 25, 21 },
[FEAT_REG_DSIPLL_REGM_DSI] = { 30, 26 },
}; };
static const struct dss_reg_field omap5_dss_reg_fields[] = { static const struct dss_reg_field omap5_dss_reg_fields[] = {
...@@ -128,10 +116,6 @@ static const struct dss_reg_field omap5_dss_reg_fields[] = { ...@@ -128,10 +116,6 @@ static const struct dss_reg_field omap5_dss_reg_fields[] = {
[FEAT_REG_HORIZONTALACCU] = { 10, 0 }, [FEAT_REG_HORIZONTALACCU] = { 10, 0 },
[FEAT_REG_VERTICALACCU] = { 26, 16 }, [FEAT_REG_VERTICALACCU] = { 26, 16 },
[FEAT_REG_DISPC_CLK_SWITCH] = { 9, 7 }, [FEAT_REG_DISPC_CLK_SWITCH] = { 9, 7 },
[FEAT_REG_DSIPLL_REGN] = { 8, 1 },
[FEAT_REG_DSIPLL_REGM] = { 20, 9 },
[FEAT_REG_DSIPLL_REGM_DISPC] = { 25, 21 },
[FEAT_REG_DSIPLL_REGM_DSI] = { 30, 26 },
}; };
static const enum omap_display_type omap2_dss_supported_displays[] = { static const enum omap_display_type omap2_dss_supported_displays[] = {
...@@ -437,12 +421,6 @@ static const char * const omap5_dss_clk_source_names[] = { ...@@ -437,12 +421,6 @@ static const char * const omap5_dss_clk_source_names[] = {
static const struct dss_param_range omap2_dss_param_range[] = { static const struct dss_param_range omap2_dss_param_range[] = {
[FEAT_PARAM_DSS_FCK] = { 0, 133000000 }, [FEAT_PARAM_DSS_FCK] = { 0, 133000000 },
[FEAT_PARAM_DSS_PCD] = { 2, 255 }, [FEAT_PARAM_DSS_PCD] = { 2, 255 },
[FEAT_PARAM_DSIPLL_REGN] = { 0, 0 },
[FEAT_PARAM_DSIPLL_REGM] = { 0, 0 },
[FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, 0 },
[FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, 0 },
[FEAT_PARAM_DSIPLL_FINT] = { 0, 0 },
[FEAT_PARAM_DSIPLL_LPDIV] = { 0, 0 },
[FEAT_PARAM_DOWNSCALE] = { 1, 2 }, [FEAT_PARAM_DOWNSCALE] = { 1, 2 },
/* /*
* Assuming the line width buffer to be 768 pixels as OMAP2 DISPC * Assuming the line width buffer to be 768 pixels as OMAP2 DISPC
...@@ -454,11 +432,6 @@ static const struct dss_param_range omap2_dss_param_range[] = { ...@@ -454,11 +432,6 @@ static const struct dss_param_range omap2_dss_param_range[] = {
static const struct dss_param_range omap3_dss_param_range[] = { static const struct dss_param_range omap3_dss_param_range[] = {
[FEAT_PARAM_DSS_FCK] = { 0, 173000000 }, [FEAT_PARAM_DSS_FCK] = { 0, 173000000 },
[FEAT_PARAM_DSS_PCD] = { 1, 255 }, [FEAT_PARAM_DSS_PCD] = { 1, 255 },
[FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 7) - 1 },
[FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 11) - 1 },
[FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 4) - 1 },
[FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 4) - 1 },
[FEAT_PARAM_DSIPLL_FINT] = { 750000, 2100000 },
[FEAT_PARAM_DSIPLL_LPDIV] = { 1, (1 << 13) - 1}, [FEAT_PARAM_DSIPLL_LPDIV] = { 1, (1 << 13) - 1},
[FEAT_PARAM_DSI_FCK] = { 0, 173000000 }, [FEAT_PARAM_DSI_FCK] = { 0, 173000000 },
[FEAT_PARAM_DOWNSCALE] = { 1, 4 }, [FEAT_PARAM_DOWNSCALE] = { 1, 4 },
...@@ -475,11 +448,6 @@ static const struct dss_param_range am43xx_dss_param_range[] = { ...@@ -475,11 +448,6 @@ static const struct dss_param_range am43xx_dss_param_range[] = {
static const struct dss_param_range omap4_dss_param_range[] = { static const struct dss_param_range omap4_dss_param_range[] = {
[FEAT_PARAM_DSS_FCK] = { 0, 186000000 }, [FEAT_PARAM_DSS_FCK] = { 0, 186000000 },
[FEAT_PARAM_DSS_PCD] = { 1, 255 }, [FEAT_PARAM_DSS_PCD] = { 1, 255 },
[FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 8) - 1 },
[FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 12) - 1 },
[FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 5) - 1 },
[FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 5) - 1 },
[FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 },
[FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 }, [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 },
[FEAT_PARAM_DSI_FCK] = { 0, 170000000 }, [FEAT_PARAM_DSI_FCK] = { 0, 170000000 },
[FEAT_PARAM_DOWNSCALE] = { 1, 4 }, [FEAT_PARAM_DOWNSCALE] = { 1, 4 },
...@@ -489,11 +457,6 @@ static const struct dss_param_range omap4_dss_param_range[] = { ...@@ -489,11 +457,6 @@ static const struct dss_param_range omap4_dss_param_range[] = {
static const struct dss_param_range omap5_dss_param_range[] = { static const struct dss_param_range omap5_dss_param_range[] = {
[FEAT_PARAM_DSS_FCK] = { 0, 209250000 }, [FEAT_PARAM_DSS_FCK] = { 0, 209250000 },
[FEAT_PARAM_DSS_PCD] = { 1, 255 }, [FEAT_PARAM_DSS_PCD] = { 1, 255 },
[FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 8) - 1 },
[FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 12) - 1 },
[FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 5) - 1 },
[FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 5) - 1 },
[FEAT_PARAM_DSIPLL_FINT] = { 150000, 52000000 },
[FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 }, [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 },
[FEAT_PARAM_DSI_FCK] = { 0, 209250000 }, [FEAT_PARAM_DSI_FCK] = { 0, 209250000 },
[FEAT_PARAM_DOWNSCALE] = { 1, 4 }, [FEAT_PARAM_DOWNSCALE] = { 1, 4 },
...@@ -517,7 +480,6 @@ static const enum dss_feat_id omap3430_dss_feat_list[] = { ...@@ -517,7 +480,6 @@ static const enum dss_feat_id omap3430_dss_feat_list[] = {
FEAT_LINEBUFFERSPLIT, FEAT_LINEBUFFERSPLIT,
FEAT_ROWREPEATENABLE, FEAT_ROWREPEATENABLE,
FEAT_RESIZECONF, FEAT_RESIZECONF,
FEAT_DSI_PLL_FREQSEL,
FEAT_DSI_REVERSE_TXCLKESC, FEAT_DSI_REVERSE_TXCLKESC,
FEAT_VENC_REQUIRES_TV_DAC_CLK, FEAT_VENC_REQUIRES_TV_DAC_CLK,
FEAT_CPR, FEAT_CPR,
...@@ -537,7 +499,6 @@ static const enum dss_feat_id am35xx_dss_feat_list[] = { ...@@ -537,7 +499,6 @@ static const enum dss_feat_id am35xx_dss_feat_list[] = {
FEAT_LINEBUFFERSPLIT, FEAT_LINEBUFFERSPLIT,
FEAT_ROWREPEATENABLE, FEAT_ROWREPEATENABLE,
FEAT_RESIZECONF, FEAT_RESIZECONF,
FEAT_DSI_PLL_FREQSEL,
FEAT_DSI_REVERSE_TXCLKESC, FEAT_DSI_REVERSE_TXCLKESC,
FEAT_VENC_REQUIRES_TV_DAC_CLK, FEAT_VENC_REQUIRES_TV_DAC_CLK,
FEAT_CPR, FEAT_CPR,
...@@ -572,7 +533,6 @@ static const enum dss_feat_id omap3630_dss_feat_list[] = { ...@@ -572,7 +533,6 @@ static const enum dss_feat_id omap3630_dss_feat_list[] = {
FEAT_ROWREPEATENABLE, FEAT_ROWREPEATENABLE,
FEAT_RESIZECONF, FEAT_RESIZECONF,
FEAT_DSI_PLL_PWR_BUG, FEAT_DSI_PLL_PWR_BUG,
FEAT_DSI_PLL_FREQSEL,
FEAT_CPR, FEAT_CPR,
FEAT_PRELOAD, FEAT_PRELOAD,
FEAT_FIR_COEF_V, FEAT_FIR_COEF_V,
...@@ -654,8 +614,6 @@ static const enum dss_feat_id omap5_dss_feat_list[] = { ...@@ -654,8 +614,6 @@ static const enum dss_feat_id omap5_dss_feat_list[] = {
FEAT_ALPHA_FREE_ZORDER, FEAT_ALPHA_FREE_ZORDER,
FEAT_FIFO_MERGE, FEAT_FIFO_MERGE,
FEAT_BURST_2D, FEAT_BURST_2D,
FEAT_DSI_PLL_SELFREQDCO,
FEAT_DSI_PLL_REFSEL,
FEAT_DSI_PHY_DCC, FEAT_DSI_PHY_DCC,
FEAT_MFLAG, FEAT_MFLAG,
}; };
......
...@@ -41,7 +41,6 @@ enum dss_feat_id { ...@@ -41,7 +41,6 @@ enum dss_feat_id {
FEAT_LCD_CLK_SRC, FEAT_LCD_CLK_SRC,
/* DSI-PLL power command 0x3 is not working */ /* DSI-PLL power command 0x3 is not working */
FEAT_DSI_PLL_PWR_BUG, FEAT_DSI_PLL_PWR_BUG,
FEAT_DSI_PLL_FREQSEL,
FEAT_DSI_DCS_CMD_CONFIG_VC, FEAT_DSI_DCS_CMD_CONFIG_VC,
FEAT_DSI_VC_OCP_WIDTH, FEAT_DSI_VC_OCP_WIDTH,
FEAT_DSI_REVERSE_TXCLKESC, FEAT_DSI_REVERSE_TXCLKESC,
...@@ -61,8 +60,6 @@ enum dss_feat_id { ...@@ -61,8 +60,6 @@ enum dss_feat_id {
/* An unknown HW bug causing the normal FIFO thresholds not to work */ /* An unknown HW bug causing the normal FIFO thresholds not to work */
FEAT_OMAP3_DSI_FIFO_BUG, FEAT_OMAP3_DSI_FIFO_BUG,
FEAT_BURST_2D, FEAT_BURST_2D,
FEAT_DSI_PLL_SELFREQDCO,
FEAT_DSI_PLL_REFSEL,
FEAT_DSI_PHY_DCC, FEAT_DSI_PHY_DCC,
FEAT_MFLAG, FEAT_MFLAG,
}; };
...@@ -77,20 +74,11 @@ enum dss_feat_reg_field { ...@@ -77,20 +74,11 @@ enum dss_feat_reg_field {
FEAT_REG_HORIZONTALACCU, FEAT_REG_HORIZONTALACCU,
FEAT_REG_VERTICALACCU, FEAT_REG_VERTICALACCU,
FEAT_REG_DISPC_CLK_SWITCH, FEAT_REG_DISPC_CLK_SWITCH,
FEAT_REG_DSIPLL_REGN,
FEAT_REG_DSIPLL_REGM,
FEAT_REG_DSIPLL_REGM_DISPC,
FEAT_REG_DSIPLL_REGM_DSI,
}; };
enum dss_range_param { enum dss_range_param {
FEAT_PARAM_DSS_FCK, FEAT_PARAM_DSS_FCK,
FEAT_PARAM_DSS_PCD, FEAT_PARAM_DSS_PCD,
FEAT_PARAM_DSIPLL_REGN,
FEAT_PARAM_DSIPLL_REGM,
FEAT_PARAM_DSIPLL_REGM_DISPC,
FEAT_PARAM_DSIPLL_REGM_DSI,
FEAT_PARAM_DSIPLL_FINT,
FEAT_PARAM_DSIPLL_LPDIV, FEAT_PARAM_DSIPLL_LPDIV,
FEAT_PARAM_DSI_FCK, FEAT_PARAM_DSI_FCK,
FEAT_PARAM_DOWNSCALE, FEAT_PARAM_DOWNSCALE,
......
...@@ -101,13 +101,6 @@ enum hdmi_core_hdmi_dvi { ...@@ -101,13 +101,6 @@ enum hdmi_core_hdmi_dvi {
HDMI_HDMI = 1 HDMI_HDMI = 1
}; };
enum hdmi_clk_refsel {
HDMI_REFSEL_PCLK = 0,
HDMI_REFSEL_REF1 = 1,
HDMI_REFSEL_REF2 = 2,
HDMI_REFSEL_SYSCLK = 3
};
enum hdmi_packing_mode { enum hdmi_packing_mode {
HDMI_PACK_10b_RGB_YUV444 = 0, HDMI_PACK_10b_RGB_YUV444 = 0,
HDMI_PACK_24b_RGB_YUV444_YUV422 = 1, HDMI_PACK_24b_RGB_YUV444_YUV422 = 1,
...@@ -160,7 +153,8 @@ enum hdmi_audio_blk_strt_end_sig { ...@@ -160,7 +153,8 @@ enum hdmi_audio_blk_strt_end_sig {
enum hdmi_core_audio_layout { enum hdmi_core_audio_layout {
HDMI_AUDIO_LAYOUT_2CH = 0, HDMI_AUDIO_LAYOUT_2CH = 0,
HDMI_AUDIO_LAYOUT_8CH = 1 HDMI_AUDIO_LAYOUT_8CH = 1,
HDMI_AUDIO_LAYOUT_6CH = 2
}; };
enum hdmi_core_cts_mode { enum hdmi_core_cts_mode {
...@@ -191,17 +185,6 @@ struct hdmi_config { ...@@ -191,17 +185,6 @@ struct hdmi_config {
enum hdmi_core_hdmi_dvi hdmi_dvi_mode; enum hdmi_core_hdmi_dvi hdmi_dvi_mode;
}; };
/* HDMI PLL structure */
struct hdmi_pll_info {
u16 regn;
u16 regm;
u32 regmf;
u16 regm2;
u16 regsd;
u16 dcofreq;
enum hdmi_clk_refsel refsel;
};
struct hdmi_audio_format { struct hdmi_audio_format {
enum hdmi_stereo_channels stereo_channels; enum hdmi_stereo_channels stereo_channels;
u8 active_chnnls_msk; u8 active_chnnls_msk;
...@@ -249,12 +232,15 @@ struct hdmi_core_audio_config { ...@@ -249,12 +232,15 @@ struct hdmi_core_audio_config {
struct hdmi_wp_data { struct hdmi_wp_data {
void __iomem *base; void __iomem *base;
phys_addr_t phys_base;
}; };
struct hdmi_pll_data { struct hdmi_pll_data {
struct dss_pll pll;
void __iomem *base; void __iomem *base;
struct hdmi_pll_info info; struct hdmi_wp_data *wp;
}; };
struct hdmi_phy_data { struct hdmi_phy_data {
...@@ -316,16 +302,19 @@ void hdmi_wp_video_config_timing(struct hdmi_wp_data *wp, ...@@ -316,16 +302,19 @@ void hdmi_wp_video_config_timing(struct hdmi_wp_data *wp,
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 omap_video_timings *timings, struct hdmi_config *param); struct omap_video_timings *timings, 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);
phys_addr_t hdmi_wp_get_audio_dma_addr(struct hdmi_wp_data *wp);
/* HDMI PLL funcs */ /* HDMI PLL funcs */
int hdmi_pll_enable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp);
void hdmi_pll_disable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp);
void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s); void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s);
void hdmi_pll_compute(struct hdmi_pll_data *pll, unsigned long clkin, int phy); void hdmi_pll_compute(struct hdmi_pll_data *pll,
int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll); unsigned long target_tmds, struct dss_pll_clock_info *pi);
int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll,
struct hdmi_wp_data *wp);
void hdmi_pll_uninit(struct hdmi_pll_data *hpll);
/* HDMI PHY funcs */ /* HDMI PHY funcs */
int hdmi_phy_configure(struct hdmi_phy_data *phy, struct hdmi_config *cfg); int hdmi_phy_configure(struct hdmi_phy_data *phy, unsigned long hfbitclk,
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);
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);
...@@ -334,7 +323,7 @@ int hdmi_phy_parse_lanes(struct hdmi_phy_data *phy, const u32 *lanes); ...@@ -334,7 +323,7 @@ int hdmi_phy_parse_lanes(struct hdmi_phy_data *phy, const u32 *lanes);
int hdmi_parse_lanes_of(struct platform_device *pdev, struct device_node *ep, int hdmi_parse_lanes_of(struct platform_device *pdev, struct device_node *ep,
struct hdmi_phy_data *phy); struct hdmi_phy_data *phy);
#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) || defined(CONFIG_OMAP5_DSS_HDMI_AUDIO) /* Audio funcs */
int hdmi_compute_acr(u32 pclk, u32 sample_freq, u32 *n, u32 *cts); int hdmi_compute_acr(u32 pclk, u32 sample_freq, u32 *n, u32 *cts);
int hdmi_wp_audio_enable(struct hdmi_wp_data *wp, bool enable); int hdmi_wp_audio_enable(struct hdmi_wp_data *wp, bool enable);
int hdmi_wp_audio_core_req_enable(struct hdmi_wp_data *wp, bool enable); int hdmi_wp_audio_core_req_enable(struct hdmi_wp_data *wp, bool enable);
...@@ -342,9 +331,33 @@ void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp, ...@@ -342,9 +331,33 @@ void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp,
struct hdmi_audio_format *aud_fmt); struct hdmi_audio_format *aud_fmt);
void hdmi_wp_audio_config_dma(struct hdmi_wp_data *wp, void hdmi_wp_audio_config_dma(struct hdmi_wp_data *wp,
struct hdmi_audio_dma *aud_dma); struct hdmi_audio_dma *aud_dma);
static inline bool hdmi_mode_has_audio(int mode) static inline bool hdmi_mode_has_audio(struct hdmi_config *cfg)
{ {
return mode == HDMI_HDMI ? true : false; return cfg->hdmi_dvi_mode == HDMI_HDMI ? true : false;
} }
#endif
/* HDMI DRV data */
struct omap_hdmi {
struct mutex lock;
struct platform_device *pdev;
struct hdmi_wp_data wp;
struct hdmi_pll_data pll;
struct hdmi_phy_data phy;
struct hdmi_core_data core;
struct hdmi_config cfg;
struct regulator *vdda_reg;
bool core_enabled;
bool display_enabled;
struct omap_dss_device output;
struct platform_device *audio_pdev;
void (*audio_abort_cb)(struct device *dev);
int wp_idlemode;
};
#endif #endif
...@@ -33,29 +33,14 @@ ...@@ -33,29 +33,14 @@
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <video/omapdss.h> #include <video/omapdss.h>
#include <sound/omap-hdmi-audio.h>
#include "hdmi4_core.h" #include "hdmi4_core.h"
#include "dss.h" #include "dss.h"
#include "dss_features.h" #include "dss_features.h"
#include "hdmi.h"
static struct { static struct omap_hdmi hdmi;
struct mutex lock;
struct platform_device *pdev;
struct hdmi_wp_data wp;
struct hdmi_pll_data pll;
struct hdmi_phy_data phy;
struct hdmi_core_data core;
struct hdmi_config cfg;
struct clk *sys_clk;
struct regulator *vdda_hdmi_dac_reg;
bool core_enabled;
struct omap_dss_device output;
} hdmi;
static int hdmi_runtime_get(void) static int hdmi_runtime_get(void)
{ {
...@@ -117,7 +102,7 @@ static int hdmi_init_regulator(void) ...@@ -117,7 +102,7 @@ static int hdmi_init_regulator(void)
int r; int r;
struct regulator *reg; struct regulator *reg;
if (hdmi.vdda_hdmi_dac_reg != NULL) if (hdmi.vdda_reg != NULL)
return 0; return 0;
reg = devm_regulator_get(&hdmi.pdev->dev, "vdda"); reg = devm_regulator_get(&hdmi.pdev->dev, "vdda");
...@@ -137,7 +122,7 @@ static int hdmi_init_regulator(void) ...@@ -137,7 +122,7 @@ static int hdmi_init_regulator(void)
} }
} }
hdmi.vdda_hdmi_dac_reg = reg; hdmi.vdda_reg = reg;
return 0; return 0;
} }
...@@ -146,7 +131,7 @@ static int hdmi_power_on_core(struct omap_dss_device *dssdev) ...@@ -146,7 +131,7 @@ static int hdmi_power_on_core(struct omap_dss_device *dssdev)
{ {
int r; int r;
r = regulator_enable(hdmi.vdda_hdmi_dac_reg); r = regulator_enable(hdmi.vdda_reg);
if (r) if (r)
return r; return r;
...@@ -162,7 +147,7 @@ static int hdmi_power_on_core(struct omap_dss_device *dssdev) ...@@ -162,7 +147,7 @@ static int hdmi_power_on_core(struct omap_dss_device *dssdev)
return 0; return 0;
err_runtime_get: err_runtime_get:
regulator_disable(hdmi.vdda_hdmi_dac_reg); regulator_disable(hdmi.vdda_reg);
return r; return r;
} }
...@@ -172,7 +157,7 @@ static void hdmi_power_off_core(struct omap_dss_device *dssdev) ...@@ -172,7 +157,7 @@ static void hdmi_power_off_core(struct omap_dss_device *dssdev)
hdmi.core_enabled = false; hdmi.core_enabled = false;
hdmi_runtime_put(); hdmi_runtime_put();
regulator_disable(hdmi.vdda_hdmi_dac_reg); regulator_disable(hdmi.vdda_reg);
} }
static int hdmi_power_on_full(struct omap_dss_device *dssdev) static int hdmi_power_on_full(struct omap_dss_device *dssdev)
...@@ -180,8 +165,8 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) ...@@ -180,8 +165,8 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
int r; int r;
struct omap_video_timings *p; struct omap_video_timings *p;
struct omap_overlay_manager *mgr = hdmi.output.manager; struct omap_overlay_manager *mgr = hdmi.output.manager;
unsigned long phy;
struct hdmi_wp_data *wp = &hdmi.wp; struct hdmi_wp_data *wp = &hdmi.wp;
struct dss_pll_clock_info hdmi_cinfo = { 0 };
r = hdmi_power_on_core(dssdev); r = hdmi_power_on_core(dssdev);
if (r) if (r)
...@@ -195,19 +180,22 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) ...@@ -195,19 +180,22 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res); DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res);
/* the functions below use kHz pixel clock. TODO: change to Hz */ hdmi_pll_compute(&hdmi.pll, p->pixelclock, &hdmi_cinfo);
phy = p->pixelclock / 1000;
hdmi_pll_compute(&hdmi.pll, clk_get_rate(hdmi.sys_clk), phy);
/* config the PLL and PHY hdmi_set_pll_pwrfirst */ r = dss_pll_enable(&hdmi.pll.pll);
r = hdmi_pll_enable(&hdmi.pll, &hdmi.wp);
if (r) { if (r) {
DSSDBG("Failed to lock PLL\n"); DSSERR("Failed to enable PLL\n");
goto err_pll_enable; goto err_pll_enable;
} }
r = hdmi_phy_configure(&hdmi.phy, &hdmi.cfg); r = dss_pll_set_config(&hdmi.pll.pll, &hdmi_cinfo);
if (r) {
DSSERR("Failed to configure PLL\n");
goto err_pll_cfg;
}
r = hdmi_phy_configure(&hdmi.phy, hdmi_cinfo.clkdco,
hdmi_cinfo.clkout[0]);
if (r) { if (r) {
DSSDBG("Failed to configure PHY\n"); DSSDBG("Failed to configure PHY\n");
goto err_phy_cfg; goto err_phy_cfg;
...@@ -244,7 +232,8 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) ...@@ -244,7 +232,8 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
err_phy_cfg: err_phy_cfg:
hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
err_phy_pwr: err_phy_pwr:
hdmi_pll_disable(&hdmi.pll, &hdmi.wp); err_pll_cfg:
dss_pll_disable(&hdmi.pll.pll);
err_pll_enable: err_pll_enable:
hdmi_power_off_core(dssdev); hdmi_power_off_core(dssdev);
return -EIO; return -EIO;
...@@ -262,7 +251,7 @@ static void hdmi_power_off_full(struct omap_dss_device *dssdev) ...@@ -262,7 +251,7 @@ static void hdmi_power_off_full(struct omap_dss_device *dssdev)
hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
hdmi_pll_disable(&hdmi.pll, &hdmi.wp); dss_pll_disable(&hdmi.pll.pll);
hdmi_power_off_core(dssdev); hdmi_power_off_core(dssdev);
} }
...@@ -352,6 +341,8 @@ static int hdmi_display_enable(struct omap_dss_device *dssdev) ...@@ -352,6 +341,8 @@ static int hdmi_display_enable(struct omap_dss_device *dssdev)
goto err0; goto err0;
} }
hdmi.display_enabled = true;
mutex_unlock(&hdmi.lock); mutex_unlock(&hdmi.lock);
return 0; return 0;
...@@ -366,8 +357,13 @@ static void hdmi_display_disable(struct omap_dss_device *dssdev) ...@@ -366,8 +357,13 @@ static void hdmi_display_disable(struct omap_dss_device *dssdev)
mutex_lock(&hdmi.lock); mutex_lock(&hdmi.lock);
if (hdmi.audio_pdev && hdmi.audio_abort_cb)
hdmi.audio_abort_cb(&hdmi.audio_pdev->dev);
hdmi_power_off_full(dssdev); hdmi_power_off_full(dssdev);
hdmi.display_enabled = false;
mutex_unlock(&hdmi.lock); mutex_unlock(&hdmi.lock);
} }
...@@ -404,21 +400,6 @@ static void hdmi_core_disable(struct omap_dss_device *dssdev) ...@@ -404,21 +400,6 @@ static void hdmi_core_disable(struct omap_dss_device *dssdev)
mutex_unlock(&hdmi.lock); mutex_unlock(&hdmi.lock);
} }
static int hdmi_get_clocks(struct platform_device *pdev)
{
struct clk *clk;
clk = devm_clk_get(&pdev->dev, "sys_clk");
if (IS_ERR(clk)) {
DSSERR("can't get sys_clk\n");
return PTR_ERR(clk);
}
hdmi.sys_clk = clk;
return 0;
}
static int hdmi_connect(struct omap_dss_device *dssdev, static int hdmi_connect(struct omap_dss_device *dssdev,
struct omap_dss_device *dst) struct omap_dss_device *dst)
{ {
...@@ -484,112 +465,6 @@ static int hdmi_read_edid(struct omap_dss_device *dssdev, ...@@ -484,112 +465,6 @@ static int hdmi_read_edid(struct omap_dss_device *dssdev,
return r; return r;
} }
#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
static int hdmi_audio_enable(struct omap_dss_device *dssdev)
{
int r;
mutex_lock(&hdmi.lock);
if (!hdmi_mode_has_audio(hdmi.cfg.hdmi_dvi_mode)) {
r = -EPERM;
goto err;
}
r = hdmi_wp_audio_enable(&hdmi.wp, true);
if (r)
goto err;
mutex_unlock(&hdmi.lock);
return 0;
err:
mutex_unlock(&hdmi.lock);
return r;
}
static void hdmi_audio_disable(struct omap_dss_device *dssdev)
{
hdmi_wp_audio_enable(&hdmi.wp, false);
}
static int hdmi_audio_start(struct omap_dss_device *dssdev)
{
return hdmi4_audio_start(&hdmi.core, &hdmi.wp);
}
static void hdmi_audio_stop(struct omap_dss_device *dssdev)
{
hdmi4_audio_stop(&hdmi.core, &hdmi.wp);
}
static bool hdmi_audio_supported(struct omap_dss_device *dssdev)
{
bool r;
mutex_lock(&hdmi.lock);
r = hdmi_mode_has_audio(hdmi.cfg.hdmi_dvi_mode);
mutex_unlock(&hdmi.lock);
return r;
}
static int hdmi_audio_config(struct omap_dss_device *dssdev,
struct omap_dss_audio *audio)
{
int r;
u32 pclk = hdmi.cfg.timings.pixelclock;
mutex_lock(&hdmi.lock);
if (!hdmi_mode_has_audio(hdmi.cfg.hdmi_dvi_mode)) {
r = -EPERM;
goto err;
}
r = hdmi4_audio_config(&hdmi.core, &hdmi.wp, audio, pclk);
if (r)
goto err;
mutex_unlock(&hdmi.lock);
return 0;
err:
mutex_unlock(&hdmi.lock);
return r;
}
#else
static int hdmi_audio_enable(struct omap_dss_device *dssdev)
{
return -EPERM;
}
static void hdmi_audio_disable(struct omap_dss_device *dssdev)
{
}
static int hdmi_audio_start(struct omap_dss_device *dssdev)
{
return -EPERM;
}
static void hdmi_audio_stop(struct omap_dss_device *dssdev)
{
}
static bool hdmi_audio_supported(struct omap_dss_device *dssdev)
{
return false;
}
static int hdmi_audio_config(struct omap_dss_device *dssdev,
struct omap_dss_audio *audio)
{
return -EPERM;
}
#endif
static int hdmi_set_infoframe(struct omap_dss_device *dssdev, static int hdmi_set_infoframe(struct omap_dss_device *dssdev,
const struct hdmi_avi_infoframe *avi) const struct hdmi_avi_infoframe *avi)
{ {
...@@ -618,13 +493,6 @@ static const struct omapdss_hdmi_ops hdmi_ops = { ...@@ -618,13 +493,6 @@ static const struct omapdss_hdmi_ops hdmi_ops = {
.read_edid = hdmi_read_edid, .read_edid = hdmi_read_edid,
.set_infoframe = hdmi_set_infoframe, .set_infoframe = hdmi_set_infoframe,
.set_hdmi_mode = hdmi_set_hdmi_mode, .set_hdmi_mode = hdmi_set_hdmi_mode,
.audio_enable = hdmi_audio_enable,
.audio_disable = hdmi_audio_disable,
.audio_start = hdmi_audio_start,
.audio_stop = hdmi_audio_stop,
.audio_supported = hdmi_audio_supported,
.audio_config = hdmi_audio_config,
}; };
static void hdmi_init_output(struct platform_device *pdev) static void hdmi_init_output(struct platform_device *pdev)
...@@ -642,7 +510,7 @@ static void hdmi_init_output(struct platform_device *pdev) ...@@ -642,7 +510,7 @@ static void hdmi_init_output(struct platform_device *pdev)
omapdss_register_output(out); omapdss_register_output(out);
} }
static void __exit hdmi_uninit_output(struct platform_device *pdev) static void hdmi_uninit_output(struct platform_device *pdev)
{ {
struct omap_dss_device *out = &hdmi.output; struct omap_dss_device *out = &hdmi.output;
...@@ -671,6 +539,112 @@ static int hdmi_probe_of(struct platform_device *pdev) ...@@ -671,6 +539,112 @@ static int hdmi_probe_of(struct platform_device *pdev)
return r; return r;
} }
/* Audio callbacks */
static int hdmi_audio_startup(struct device *dev,
void (*abort_cb)(struct device *dev))
{
struct omap_hdmi *hd = dev_get_drvdata(dev);
int ret = 0;
mutex_lock(&hd->lock);
if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) {
ret = -EPERM;
goto out;
}
hd->audio_abort_cb = abort_cb;
out:
mutex_unlock(&hd->lock);
return ret;
}
static int hdmi_audio_shutdown(struct device *dev)
{
struct omap_hdmi *hd = dev_get_drvdata(dev);
mutex_lock(&hd->lock);
hd->audio_abort_cb = NULL;
mutex_unlock(&hd->lock);
return 0;
}
static int hdmi_audio_start(struct device *dev)
{
struct omap_hdmi *hd = dev_get_drvdata(dev);
WARN_ON(!hdmi_mode_has_audio(&hd->cfg));
WARN_ON(!hd->display_enabled);
hdmi_wp_audio_enable(&hd->wp, true);
hdmi4_audio_start(&hd->core, &hd->wp);
return 0;
}
static void hdmi_audio_stop(struct device *dev)
{
struct omap_hdmi *hd = dev_get_drvdata(dev);
WARN_ON(!hdmi_mode_has_audio(&hd->cfg));
WARN_ON(!hd->display_enabled);
hdmi4_audio_stop(&hd->core, &hd->wp);
hdmi_wp_audio_enable(&hd->wp, false);
}
static int hdmi_audio_config(struct device *dev,
struct omap_dss_audio *dss_audio)
{
struct omap_hdmi *hd = dev_get_drvdata(dev);
int ret;
mutex_lock(&hd->lock);
if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) {
ret = -EPERM;
goto out;
}
ret = hdmi4_audio_config(&hd->core, &hd->wp, dss_audio,
hd->cfg.timings.pixelclock);
out:
mutex_unlock(&hd->lock);
return ret;
}
static const struct omap_hdmi_audio_ops hdmi_audio_ops = {
.audio_startup = hdmi_audio_startup,
.audio_shutdown = hdmi_audio_shutdown,
.audio_start = hdmi_audio_start,
.audio_stop = hdmi_audio_stop,
.audio_config = hdmi_audio_config,
};
static int hdmi_audio_register(struct device *dev)
{
struct omap_hdmi_audio_pdata pdata = {
.dev = dev,
.dss_version = omapdss_get_version(),
.audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi.wp),
.ops = &hdmi_audio_ops,
};
hdmi.audio_pdev = platform_device_register_data(
dev, "omap-hdmi-audio", PLATFORM_DEVID_AUTO,
&pdata, sizeof(pdata));
if (IS_ERR(hdmi.audio_pdev))
return PTR_ERR(hdmi.audio_pdev);
return 0;
}
/* HDMI HW IP initialisation */ /* HDMI HW IP initialisation */
static int omapdss_hdmihw_probe(struct platform_device *pdev) static int omapdss_hdmihw_probe(struct platform_device *pdev)
{ {
...@@ -678,6 +652,7 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev) ...@@ -678,6 +652,7 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
int irq; int irq;
hdmi.pdev = pdev; hdmi.pdev = pdev;
dev_set_drvdata(&pdev->dev, &hdmi);
mutex_init(&hdmi.lock); mutex_init(&hdmi.lock);
...@@ -691,28 +666,23 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev) ...@@ -691,28 +666,23 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
if (r) if (r)
return r; return r;
r = hdmi_pll_init(pdev, &hdmi.pll); r = hdmi_pll_init(pdev, &hdmi.pll, &hdmi.wp);
if (r) if (r)
return r; return r;
r = hdmi_phy_init(pdev, &hdmi.phy); r = hdmi_phy_init(pdev, &hdmi.phy);
if (r) if (r)
return r; goto err;
r = hdmi4_core_init(pdev, &hdmi.core); r = hdmi4_core_init(pdev, &hdmi.core);
if (r) if (r)
return r; goto err;
r = hdmi_get_clocks(pdev);
if (r) {
DSSERR("can't get clocks\n");
return r;
}
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq < 0) { if (irq < 0) {
DSSERR("platform_get_irq failed\n"); DSSERR("platform_get_irq failed\n");
return -ENODEV; r = -ENODEV;
goto err;
} }
r = devm_request_threaded_irq(&pdev->dev, irq, r = devm_request_threaded_irq(&pdev->dev, irq,
...@@ -720,22 +690,38 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev) ...@@ -720,22 +690,38 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
IRQF_ONESHOT, "OMAP HDMI", &hdmi.wp); IRQF_ONESHOT, "OMAP HDMI", &hdmi.wp);
if (r) { if (r) {
DSSERR("HDMI IRQ request failed\n"); DSSERR("HDMI IRQ request failed\n");
return r; goto err;
} }
pm_runtime_enable(&pdev->dev); pm_runtime_enable(&pdev->dev);
hdmi_init_output(pdev); hdmi_init_output(pdev);
r = hdmi_audio_register(&pdev->dev);
if (r) {
DSSERR("Registering HDMI audio failed\n");
hdmi_uninit_output(pdev);
pm_runtime_disable(&pdev->dev);
return r;
}
dss_debugfs_create_file("hdmi", hdmi_dump_regs); dss_debugfs_create_file("hdmi", hdmi_dump_regs);
return 0; return 0;
err:
hdmi_pll_uninit(&hdmi.pll);
return r;
} }
static int __exit omapdss_hdmihw_remove(struct platform_device *pdev) static int __exit omapdss_hdmihw_remove(struct platform_device *pdev)
{ {
if (hdmi.audio_pdev)
platform_device_unregister(hdmi.audio_pdev);
hdmi_uninit_output(pdev); hdmi_uninit_output(pdev);
hdmi_pll_uninit(&hdmi.pll);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
return 0; return 0;
...@@ -743,8 +729,6 @@ static int __exit omapdss_hdmihw_remove(struct platform_device *pdev) ...@@ -743,8 +729,6 @@ static int __exit omapdss_hdmihw_remove(struct platform_device *pdev)
static int hdmi_runtime_suspend(struct device *dev) static int hdmi_runtime_suspend(struct device *dev)
{ {
clk_disable_unprepare(hdmi.sys_clk);
dispc_runtime_put(); dispc_runtime_put();
return 0; return 0;
...@@ -758,8 +742,6 @@ static int hdmi_runtime_resume(struct device *dev) ...@@ -758,8 +742,6 @@ static int hdmi_runtime_resume(struct device *dev)
if (r < 0) if (r < 0)
return r; return r;
clk_prepare_enable(hdmi.sys_clk);
return 0; return 0;
} }
......
...@@ -31,10 +31,8 @@ ...@@ -31,10 +31,8 @@
#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>
#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
#include <sound/asound.h> #include <sound/asound.h>
#include <sound/asoundef.h> #include <sound/asoundef.h>
#endif
#include "hdmi4_core.h" #include "hdmi4_core.h"
#include "dss_features.h" #include "dss_features.h"
...@@ -530,7 +528,6 @@ void hdmi4_core_dump(struct hdmi_core_data *core, struct seq_file *s) ...@@ -530,7 +528,6 @@ void hdmi4_core_dump(struct hdmi_core_data *core, struct seq_file *s)
DUMPCOREAV(HDMI_CORE_AV_CEC_ADDR_ID); DUMPCOREAV(HDMI_CORE_AV_CEC_ADDR_ID);
} }
#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
static void hdmi_core_audio_config(struct hdmi_core_data *core, static void hdmi_core_audio_config(struct hdmi_core_data *core,
struct hdmi_core_audio_config *cfg) struct hdmi_core_audio_config *cfg)
{ {
...@@ -877,17 +874,6 @@ void hdmi4_audio_stop(struct hdmi_core_data *core, struct hdmi_wp_data *wp) ...@@ -877,17 +874,6 @@ 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);
} }
int hdmi4_audio_get_dma_port(u32 *offset, u32 *size)
{
if (!offset || !size)
return -EINVAL;
*offset = HDMI_WP_AUDIO_DATA;
*size = 4;
return 0;
}
#endif
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)
{ {
struct resource *res; struct resource *res;
......
...@@ -266,12 +266,8 @@ void hdmi4_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp, ...@@ -266,12 +266,8 @@ void hdmi4_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
void hdmi4_core_dump(struct hdmi_core_data *core, struct seq_file *s); void hdmi4_core_dump(struct hdmi_core_data *core, struct seq_file *s);
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);
#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
int hdmi4_audio_start(struct hdmi_core_data *core, struct hdmi_wp_data *wp); int hdmi4_audio_start(struct hdmi_core_data *core, struct hdmi_wp_data *wp);
void hdmi4_audio_stop(struct hdmi_core_data *core, struct hdmi_wp_data *wp); void hdmi4_audio_stop(struct hdmi_core_data *core, struct hdmi_wp_data *wp);
int hdmi4_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp, int hdmi4_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
struct omap_dss_audio *audio, u32 pclk); struct omap_dss_audio *audio, u32 pclk);
int hdmi4_audio_get_dma_port(u32 *offset, u32 *size);
#endif
#endif #endif
...@@ -38,29 +38,13 @@ ...@@ -38,29 +38,13 @@
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <video/omapdss.h> #include <video/omapdss.h>
#include <sound/omap-hdmi-audio.h>
#include "hdmi5_core.h" #include "hdmi5_core.h"
#include "dss.h" #include "dss.h"
#include "dss_features.h" #include "dss_features.h"
static struct { static struct omap_hdmi hdmi;
struct mutex lock;
struct platform_device *pdev;
struct hdmi_wp_data wp;
struct hdmi_pll_data pll;
struct hdmi_phy_data phy;
struct hdmi_core_data core;
struct hdmi_config cfg;
struct clk *sys_clk;
struct regulator *vdda_reg;
bool core_enabled;
struct omap_dss_device output;
} hdmi;
static int hdmi_runtime_get(void) static int hdmi_runtime_get(void)
{ {
...@@ -198,7 +182,7 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) ...@@ -198,7 +182,7 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
int r; int r;
struct omap_video_timings *p; struct omap_video_timings *p;
struct omap_overlay_manager *mgr = hdmi.output.manager; struct omap_overlay_manager *mgr = hdmi.output.manager;
unsigned long phy; struct dss_pll_clock_info hdmi_cinfo = { 0 };
r = hdmi_power_on_core(dssdev); r = hdmi_power_on_core(dssdev);
if (r) if (r)
...@@ -208,24 +192,27 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) ...@@ -208,24 +192,27 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res); DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res);
/* the functions below use kHz pixel clock. TODO: change to Hz */ hdmi_pll_compute(&hdmi.pll, p->pixelclock, &hdmi_cinfo);
phy = p->pixelclock / 1000;
hdmi_pll_compute(&hdmi.pll, clk_get_rate(hdmi.sys_clk), phy);
/* disable and clear irqs */ /* disable and clear irqs */
hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff); hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff);
hdmi_wp_set_irqstatus(&hdmi.wp, hdmi_wp_set_irqstatus(&hdmi.wp,
hdmi_wp_get_irqstatus(&hdmi.wp)); hdmi_wp_get_irqstatus(&hdmi.wp));
/* config the PLL and PHY hdmi_set_pll_pwrfirst */ r = dss_pll_enable(&hdmi.pll.pll);
r = hdmi_pll_enable(&hdmi.pll, &hdmi.wp);
if (r) { if (r) {
DSSDBG("Failed to lock PLL\n"); DSSERR("Failed to enable PLL\n");
goto err_pll_enable; goto err_pll_enable;
} }
r = hdmi_phy_configure(&hdmi.phy, &hdmi.cfg); r = dss_pll_set_config(&hdmi.pll.pll, &hdmi_cinfo);
if (r) {
DSSERR("Failed to configure PLL\n");
goto err_pll_cfg;
}
r = hdmi_phy_configure(&hdmi.phy, hdmi_cinfo.clkdco,
hdmi_cinfo.clkout[0]);
if (r) { if (r) {
DSSDBG("Failed to start PHY\n"); DSSDBG("Failed to start PHY\n");
goto err_phy_cfg; goto err_phy_cfg;
...@@ -262,7 +249,8 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) ...@@ -262,7 +249,8 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
err_phy_pwr: err_phy_pwr:
err_phy_cfg: err_phy_cfg:
hdmi_pll_disable(&hdmi.pll, &hdmi.wp); err_pll_cfg:
dss_pll_disable(&hdmi.pll.pll);
err_pll_enable: err_pll_enable:
hdmi_power_off_core(dssdev); hdmi_power_off_core(dssdev);
return -EIO; return -EIO;
...@@ -280,7 +268,7 @@ static void hdmi_power_off_full(struct omap_dss_device *dssdev) ...@@ -280,7 +268,7 @@ static void hdmi_power_off_full(struct omap_dss_device *dssdev)
hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
hdmi_pll_disable(&hdmi.pll, &hdmi.wp); dss_pll_disable(&hdmi.pll.pll);
hdmi_power_off_core(dssdev); hdmi_power_off_core(dssdev);
} }
...@@ -290,6 +278,10 @@ static int hdmi_display_check_timing(struct omap_dss_device *dssdev, ...@@ -290,6 +278,10 @@ static int hdmi_display_check_timing(struct omap_dss_device *dssdev,
{ {
struct omap_dss_device *out = &hdmi.output; struct omap_dss_device *out = &hdmi.output;
/* TODO: proper interlace support */
if (timings->interlace)
return -EINVAL;
if (!dispc_mgr_timings_ok(out->dispc_channel, timings)) if (!dispc_mgr_timings_ok(out->dispc_channel, timings))
return -EINVAL; return -EINVAL;
...@@ -377,6 +369,8 @@ static int hdmi_display_enable(struct omap_dss_device *dssdev) ...@@ -377,6 +369,8 @@ static int hdmi_display_enable(struct omap_dss_device *dssdev)
goto err0; goto err0;
} }
hdmi.display_enabled = true;
mutex_unlock(&hdmi.lock); mutex_unlock(&hdmi.lock);
return 0; return 0;
...@@ -391,8 +385,13 @@ static void hdmi_display_disable(struct omap_dss_device *dssdev) ...@@ -391,8 +385,13 @@ static void hdmi_display_disable(struct omap_dss_device *dssdev)
mutex_lock(&hdmi.lock); mutex_lock(&hdmi.lock);
if (hdmi.audio_pdev && hdmi.audio_abort_cb)
hdmi.audio_abort_cb(&hdmi.audio_pdev->dev);
hdmi_power_off_full(dssdev); hdmi_power_off_full(dssdev);
hdmi.display_enabled = false;
mutex_unlock(&hdmi.lock); mutex_unlock(&hdmi.lock);
} }
...@@ -429,21 +428,6 @@ static void hdmi_core_disable(struct omap_dss_device *dssdev) ...@@ -429,21 +428,6 @@ static void hdmi_core_disable(struct omap_dss_device *dssdev)
mutex_unlock(&hdmi.lock); mutex_unlock(&hdmi.lock);
} }
static int hdmi_get_clocks(struct platform_device *pdev)
{
struct clk *clk;
clk = devm_clk_get(&pdev->dev, "sys_clk");
if (IS_ERR(clk)) {
DSSERR("can't get sys_clk\n");
return PTR_ERR(clk);
}
hdmi.sys_clk = clk;
return 0;
}
static int hdmi_connect(struct omap_dss_device *dssdev, static int hdmi_connect(struct omap_dss_device *dssdev,
struct omap_dss_device *dst) struct omap_dss_device *dst)
{ {
...@@ -509,112 +493,6 @@ static int hdmi_read_edid(struct omap_dss_device *dssdev, ...@@ -509,112 +493,6 @@ static int hdmi_read_edid(struct omap_dss_device *dssdev,
return r; return r;
} }
#if defined(CONFIG_OMAP5_DSS_HDMI_AUDIO)
static int hdmi_audio_enable(struct omap_dss_device *dssdev)
{
int r;
mutex_lock(&hdmi.lock);
if (!hdmi_mode_has_audio(hdmi.cfg.hdmi_dvi_mode)) {
r = -EPERM;
goto err;
}
r = hdmi_wp_audio_enable(&hdmi.wp, true);
if (r)
goto err;
mutex_unlock(&hdmi.lock);
return 0;
err:
mutex_unlock(&hdmi.lock);
return r;
}
static void hdmi_audio_disable(struct omap_dss_device *dssdev)
{
hdmi_wp_audio_enable(&hdmi.wp, false);
}
static int hdmi_audio_start(struct omap_dss_device *dssdev)
{
return hdmi_wp_audio_core_req_enable(&hdmi.wp, true);
}
static void hdmi_audio_stop(struct omap_dss_device *dssdev)
{
hdmi_wp_audio_core_req_enable(&hdmi.wp, false);
}
static bool hdmi_audio_supported(struct omap_dss_device *dssdev)
{
bool r;
mutex_lock(&hdmi.lock);
r = hdmi_mode_has_audio(hdmi.cfg.hdmi_dvi_mode);
mutex_unlock(&hdmi.lock);
return r;
}
static int hdmi_audio_config(struct omap_dss_device *dssdev,
struct omap_dss_audio *audio)
{
int r;
u32 pclk = hdmi.cfg.timings.pixelclock;
mutex_lock(&hdmi.lock);
if (!hdmi_mode_has_audio(hdmi.cfg.hdmi_dvi_mode)) {
r = -EPERM;
goto err;
}
r = hdmi5_audio_config(&hdmi.core, &hdmi.wp, audio, pclk);
if (r)
goto err;
mutex_unlock(&hdmi.lock);
return 0;
err:
mutex_unlock(&hdmi.lock);
return r;
}
#else
static int hdmi_audio_enable(struct omap_dss_device *dssdev)
{
return -EPERM;
}
static void hdmi_audio_disable(struct omap_dss_device *dssdev)
{
}
static int hdmi_audio_start(struct omap_dss_device *dssdev)
{
return -EPERM;
}
static void hdmi_audio_stop(struct omap_dss_device *dssdev)
{
}
static bool hdmi_audio_supported(struct omap_dss_device *dssdev)
{
return false;
}
static int hdmi_audio_config(struct omap_dss_device *dssdev,
struct omap_dss_audio *audio)
{
return -EPERM;
}
#endif
static int hdmi_set_infoframe(struct omap_dss_device *dssdev, static int hdmi_set_infoframe(struct omap_dss_device *dssdev,
const struct hdmi_avi_infoframe *avi) const struct hdmi_avi_infoframe *avi)
{ {
...@@ -643,13 +521,6 @@ static const struct omapdss_hdmi_ops hdmi_ops = { ...@@ -643,13 +521,6 @@ static const struct omapdss_hdmi_ops hdmi_ops = {
.read_edid = hdmi_read_edid, .read_edid = hdmi_read_edid,
.set_infoframe = hdmi_set_infoframe, .set_infoframe = hdmi_set_infoframe,
.set_hdmi_mode = hdmi_set_hdmi_mode, .set_hdmi_mode = hdmi_set_hdmi_mode,
.audio_enable = hdmi_audio_enable,
.audio_disable = hdmi_audio_disable,
.audio_start = hdmi_audio_start,
.audio_stop = hdmi_audio_stop,
.audio_supported = hdmi_audio_supported,
.audio_config = hdmi_audio_config,
}; };
static void hdmi_init_output(struct platform_device *pdev) static void hdmi_init_output(struct platform_device *pdev)
...@@ -667,7 +538,7 @@ static void hdmi_init_output(struct platform_device *pdev) ...@@ -667,7 +538,7 @@ static void hdmi_init_output(struct platform_device *pdev)
omapdss_register_output(out); omapdss_register_output(out);
} }
static void __exit hdmi_uninit_output(struct platform_device *pdev) static void hdmi_uninit_output(struct platform_device *pdev)
{ {
struct omap_dss_device *out = &hdmi.output; struct omap_dss_device *out = &hdmi.output;
...@@ -696,6 +567,119 @@ static int hdmi_probe_of(struct platform_device *pdev) ...@@ -696,6 +567,119 @@ static int hdmi_probe_of(struct platform_device *pdev)
return r; return r;
} }
/* Audio callbacks */
static int hdmi_audio_startup(struct device *dev,
void (*abort_cb)(struct device *dev))
{
struct omap_hdmi *hd = dev_get_drvdata(dev);
int ret = 0;
mutex_lock(&hd->lock);
if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) {
ret = -EPERM;
goto out;
}
hd->audio_abort_cb = abort_cb;
out:
mutex_unlock(&hd->lock);
return ret;
}
static int hdmi_audio_shutdown(struct device *dev)
{
struct omap_hdmi *hd = dev_get_drvdata(dev);
mutex_lock(&hd->lock);
hd->audio_abort_cb = NULL;
mutex_unlock(&hd->lock);
return 0;
}
static int hdmi_audio_start(struct device *dev)
{
struct omap_hdmi *hd = dev_get_drvdata(dev);
WARN_ON(!hdmi_mode_has_audio(&hd->cfg));
WARN_ON(!hd->display_enabled);
/* No-idle while playing audio, store the old value */
hd->wp_idlemode = REG_GET(hdmi.wp.base, HDMI_WP_SYSCONFIG, 3, 2);
REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2);
hdmi_wp_audio_enable(&hd->wp, true);
hdmi_wp_audio_core_req_enable(&hd->wp, true);
return 0;
}
static void hdmi_audio_stop(struct device *dev)
{
struct omap_hdmi *hd = dev_get_drvdata(dev);
WARN_ON(!hdmi_mode_has_audio(&hd->cfg));
WARN_ON(!hd->display_enabled);
hdmi_wp_audio_core_req_enable(&hd->wp, false);
hdmi_wp_audio_enable(&hd->wp, false);
/* Playback stopped, restore original idlemode */
REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, hd->wp_idlemode, 3, 2);
}
static int hdmi_audio_config(struct device *dev,
struct omap_dss_audio *dss_audio)
{
struct omap_hdmi *hd = dev_get_drvdata(dev);
int ret;
mutex_lock(&hd->lock);
if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) {
ret = -EPERM;
goto out;
}
ret = hdmi5_audio_config(&hd->core, &hd->wp, dss_audio,
hd->cfg.timings.pixelclock);
out:
mutex_unlock(&hd->lock);
return ret;
}
static const struct omap_hdmi_audio_ops hdmi_audio_ops = {
.audio_startup = hdmi_audio_startup,
.audio_shutdown = hdmi_audio_shutdown,
.audio_start = hdmi_audio_start,
.audio_stop = hdmi_audio_stop,
.audio_config = hdmi_audio_config,
};
static int hdmi_audio_register(struct device *dev)
{
struct omap_hdmi_audio_pdata pdata = {
.dev = dev,
.dss_version = omapdss_get_version(),
.audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi.wp),
.ops = &hdmi_audio_ops,
};
hdmi.audio_pdev = platform_device_register_data(
dev, "omap-hdmi-audio", PLATFORM_DEVID_AUTO,
&pdata, sizeof(pdata));
if (IS_ERR(hdmi.audio_pdev))
return PTR_ERR(hdmi.audio_pdev);
return 0;
}
/* HDMI HW IP initialisation */ /* HDMI HW IP initialisation */
static int omapdss_hdmihw_probe(struct platform_device *pdev) static int omapdss_hdmihw_probe(struct platform_device *pdev)
{ {
...@@ -703,6 +687,7 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev) ...@@ -703,6 +687,7 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
int irq; int irq;
hdmi.pdev = pdev; hdmi.pdev = pdev;
dev_set_drvdata(&pdev->dev, &hdmi);
mutex_init(&hdmi.lock); mutex_init(&hdmi.lock);
...@@ -716,28 +701,23 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev) ...@@ -716,28 +701,23 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
if (r) if (r)
return r; return r;
r = hdmi_pll_init(pdev, &hdmi.pll); r = hdmi_pll_init(pdev, &hdmi.pll, &hdmi.wp);
if (r) if (r)
return r; return r;
r = hdmi_phy_init(pdev, &hdmi.phy); r = hdmi_phy_init(pdev, &hdmi.phy);
if (r) if (r)
return r; goto err;
r = hdmi5_core_init(pdev, &hdmi.core); r = hdmi5_core_init(pdev, &hdmi.core);
if (r) if (r)
return r; goto err;
r = hdmi_get_clocks(pdev);
if (r) {
DSSERR("can't get clocks\n");
return r;
}
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq < 0) { if (irq < 0) {
DSSERR("platform_get_irq failed\n"); DSSERR("platform_get_irq failed\n");
return -ENODEV; r = -ENODEV;
goto err;
} }
r = devm_request_threaded_irq(&pdev->dev, irq, r = devm_request_threaded_irq(&pdev->dev, irq,
...@@ -745,22 +725,38 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev) ...@@ -745,22 +725,38 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
IRQF_ONESHOT, "OMAP HDMI", &hdmi.wp); IRQF_ONESHOT, "OMAP HDMI", &hdmi.wp);
if (r) { if (r) {
DSSERR("HDMI IRQ request failed\n"); DSSERR("HDMI IRQ request failed\n");
return r; goto err;
} }
pm_runtime_enable(&pdev->dev); pm_runtime_enable(&pdev->dev);
hdmi_init_output(pdev); hdmi_init_output(pdev);
r = hdmi_audio_register(&pdev->dev);
if (r) {
DSSERR("Registering HDMI audio failed %d\n", r);
hdmi_uninit_output(pdev);
pm_runtime_disable(&pdev->dev);
return r;
}
dss_debugfs_create_file("hdmi", hdmi_dump_regs); dss_debugfs_create_file("hdmi", hdmi_dump_regs);
return 0; return 0;
err:
hdmi_pll_uninit(&hdmi.pll);
return r;
} }
static int __exit omapdss_hdmihw_remove(struct platform_device *pdev) static int __exit omapdss_hdmihw_remove(struct platform_device *pdev)
{ {
if (hdmi.audio_pdev)
platform_device_unregister(hdmi.audio_pdev);
hdmi_uninit_output(pdev); hdmi_uninit_output(pdev);
hdmi_pll_uninit(&hdmi.pll);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
return 0; return 0;
...@@ -768,8 +764,6 @@ static int __exit omapdss_hdmihw_remove(struct platform_device *pdev) ...@@ -768,8 +764,6 @@ static int __exit omapdss_hdmihw_remove(struct platform_device *pdev)
static int hdmi_runtime_suspend(struct device *dev) static int hdmi_runtime_suspend(struct device *dev)
{ {
clk_disable_unprepare(hdmi.sys_clk);
dispc_runtime_put(); dispc_runtime_put();
return 0; return 0;
...@@ -783,8 +777,6 @@ static int hdmi_runtime_resume(struct device *dev) ...@@ -783,8 +777,6 @@ static int hdmi_runtime_resume(struct device *dev)
if (r < 0) if (r < 0)
return r; return r;
clk_prepare_enable(hdmi.sys_clk);
return 0; return 0;
} }
......
...@@ -30,10 +30,8 @@ ...@@ -30,10 +30,8 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <drm/drm_edid.h> #include <drm/drm_edid.h>
#if defined(CONFIG_OMAP5_DSS_HDMI_AUDIO)
#include <sound/asound.h> #include <sound/asound.h>
#include <sound/asoundef.h> #include <sound/asoundef.h>
#endif
#include "hdmi5_core.h" #include "hdmi5_core.h"
...@@ -644,9 +642,6 @@ void hdmi5_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp, ...@@ -644,9 +642,6 @@ void hdmi5_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
hdmi_core_enable_interrupts(core); hdmi_core_enable_interrupts(core);
} }
#if defined(CONFIG_OMAP5_DSS_HDMI_AUDIO)
static void hdmi5_core_audio_config(struct hdmi_core_data *core, static void hdmi5_core_audio_config(struct hdmi_core_data *core,
struct hdmi_core_audio_config *cfg) struct hdmi_core_audio_config *cfg)
{ {
...@@ -721,7 +716,7 @@ static void hdmi5_core_audio_config(struct hdmi_core_data *core, ...@@ -721,7 +716,7 @@ static void hdmi5_core_audio_config(struct hdmi_core_data *core,
/* Source number */ /* Source number */
val = cfg->iec60958_cfg->status[2] & IEC958_AES2_CON_SOURCE; val = cfg->iec60958_cfg->status[2] & IEC958_AES2_CON_SOURCE;
REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(2), val, 3, 4); REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(2), val, 3, 0);
/* Channel number right 0 */ /* Channel number right 0 */
REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(3), 2, 3, 0); REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(3), 2, 3, 0);
...@@ -879,6 +874,9 @@ int hdmi5_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp, ...@@ -879,6 +874,9 @@ int hdmi5_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
/* only LPCM atm */ /* only LPCM atm */
audio_format.type = HDMI_AUDIO_TYPE_LPCM; audio_format.type = HDMI_AUDIO_TYPE_LPCM;
/* only allowed option */
audio_format.sample_order = HDMI_AUDIO_SAMPLE_LEFT_FIRST;
/* disable start/stop signals of IEC 60958 blocks */ /* disable start/stop signals of IEC 60958 blocks */
audio_format.en_sig_blk_strt_end = HDMI_AUDIO_BLOCK_SIG_STARTEND_ON; audio_format.en_sig_blk_strt_end = HDMI_AUDIO_BLOCK_SIG_STARTEND_ON;
...@@ -894,7 +892,6 @@ int hdmi5_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp, ...@@ -894,7 +892,6 @@ int hdmi5_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
return 0; return 0;
} }
#endif
int hdmi5_core_init(struct platform_device *pdev, struct hdmi_core_data *core) int hdmi5_core_init(struct platform_device *pdev, struct hdmi_core_data *core)
{ {
......
...@@ -299,8 +299,6 @@ void hdmi5_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp, ...@@ -299,8 +299,6 @@ void hdmi5_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
struct hdmi_config *cfg); struct hdmi_config *cfg);
int hdmi5_core_init(struct platform_device *pdev, struct hdmi_core_data *core); int hdmi5_core_init(struct platform_device *pdev, struct hdmi_core_data *core);
#if defined(CONFIG_OMAP5_DSS_HDMI_AUDIO)
int hdmi5_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp, int hdmi5_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
struct omap_dss_audio *audio, u32 pclk); struct omap_dss_audio *audio, u32 pclk);
#endif #endif
#endif
...@@ -48,7 +48,6 @@ int hdmi_parse_lanes_of(struct platform_device *pdev, struct device_node *ep, ...@@ -48,7 +48,6 @@ int hdmi_parse_lanes_of(struct platform_device *pdev, struct device_node *ep,
return 0; return 0;
} }
#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
int hdmi_compute_acr(u32 pclk, u32 sample_freq, u32 *n, u32 *cts) int hdmi_compute_acr(u32 pclk, u32 sample_freq, u32 *n, u32 *cts)
{ {
u32 deep_color; u32 deep_color;
...@@ -147,4 +146,3 @@ int hdmi_compute_acr(u32 pclk, u32 sample_freq, u32 *n, u32 *cts) ...@@ -147,4 +146,3 @@ int hdmi_compute_acr(u32 pclk, u32 sample_freq, u32 *n, u32 *cts)
return 0; return 0;
} }
#endif
...@@ -20,9 +20,7 @@ ...@@ -20,9 +20,7 @@
struct hdmi_phy_features { struct hdmi_phy_features {
bool bist_ctrl; bool bist_ctrl;
bool calc_freqout;
bool ldo_voltage; bool ldo_voltage;
unsigned long dcofreq_min;
unsigned long max_phy; unsigned long max_phy;
}; };
...@@ -132,7 +130,8 @@ static void hdmi_phy_configure_lanes(struct hdmi_phy_data *phy) ...@@ -132,7 +130,8 @@ static void hdmi_phy_configure_lanes(struct hdmi_phy_data *phy)
REG_FLD_MOD(phy->base, HDMI_TXPHY_PAD_CFG_CTRL, pol_val, 30, 27); REG_FLD_MOD(phy->base, HDMI_TXPHY_PAD_CFG_CTRL, pol_val, 30, 27);
} }
int hdmi_phy_configure(struct hdmi_phy_data *phy, struct hdmi_config *cfg) int hdmi_phy_configure(struct hdmi_phy_data *phy, unsigned long hfbitclk,
unsigned long lfbitclk)
{ {
u8 freqout; u8 freqout;
...@@ -149,20 +148,16 @@ int hdmi_phy_configure(struct hdmi_phy_data *phy, struct hdmi_config *cfg) ...@@ -149,20 +148,16 @@ int hdmi_phy_configure(struct hdmi_phy_data *phy, struct hdmi_config *cfg)
if (phy_feat->bist_ctrl) if (phy_feat->bist_ctrl)
REG_FLD_MOD(phy->base, HDMI_TXPHY_BIST_CONTROL, 1, 11, 11); REG_FLD_MOD(phy->base, HDMI_TXPHY_BIST_CONTROL, 1, 11, 11);
if (phy_feat->calc_freqout) { /*
/* DCOCLK/10 is pixel clock, compare pclk with DCOCLK_MIN/10 */ * If the hfbitclk != lfbitclk, it means the lfbitclk was configured
u32 dco_min = phy_feat->dcofreq_min / 10; * to be used for TMDS.
u32 pclk = cfg->timings.pixelclock; */
if (hfbitclk != lfbitclk)
if (pclk < dco_min) freqout = 0;
freqout = 0; else if (hfbitclk / 10 < phy_feat->max_phy)
else if ((pclk >= dco_min) && (pclk < phy_feat->max_phy))
freqout = 1;
else
freqout = 2;
} else {
freqout = 1; freqout = 1;
} else
freqout = 2;
/* /*
* Write to phy address 0 to configure the clock * Write to phy address 0 to configure the clock
...@@ -184,17 +179,13 @@ int hdmi_phy_configure(struct hdmi_phy_data *phy, struct hdmi_config *cfg) ...@@ -184,17 +179,13 @@ int hdmi_phy_configure(struct hdmi_phy_data *phy, struct hdmi_config *cfg)
static const struct hdmi_phy_features omap44xx_phy_feats = { static const struct hdmi_phy_features omap44xx_phy_feats = {
.bist_ctrl = false, .bist_ctrl = false,
.calc_freqout = false,
.ldo_voltage = true, .ldo_voltage = true,
.dcofreq_min = 500000000,
.max_phy = 185675000, .max_phy = 185675000,
}; };
static const struct hdmi_phy_features omap54xx_phy_feats = { static const struct hdmi_phy_features omap54xx_phy_feats = {
.bist_ctrl = true, .bist_ctrl = true,
.calc_freqout = true,
.ldo_voltage = false, .ldo_voltage = false,
.dcofreq_min = 750000000,
.max_phy = 186000000, .max_phy = 186000000,
}; };
......
...@@ -15,26 +15,13 @@ ...@@ -15,26 +15,13 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/clk.h>
#include <video/omapdss.h> #include <video/omapdss.h>
#include "dss.h" #include "dss.h"
#include "hdmi.h" #include "hdmi.h"
#define HDMI_DEFAULT_REGN 16
#define HDMI_DEFAULT_REGM2 1
struct hdmi_pll_features {
bool sys_reset;
/* this is a hack, need to replace it with a better computation of M2 */
bool bound_dcofreq;
unsigned long fint_min, fint_max;
u16 regm_max;
unsigned long dcofreq_low_min, dcofreq_low_max;
unsigned long dcofreq_high_min, dcofreq_high_max;
};
static const struct hdmi_pll_features *pll_feat;
void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s) void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s)
{ {
#define DUMPPLL(r) seq_printf(s, "%-35s %08x\n", #r,\ #define DUMPPLL(r) seq_printf(s, "%-35s %08x\n", #r,\
...@@ -51,228 +38,189 @@ void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s) ...@@ -51,228 +38,189 @@ void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s)
DUMPPLL(PLLCTRL_CFG4); DUMPPLL(PLLCTRL_CFG4);
} }
void hdmi_pll_compute(struct hdmi_pll_data *pll, unsigned long clkin, int phy) void hdmi_pll_compute(struct hdmi_pll_data *pll,
unsigned long target_tmds, struct dss_pll_clock_info *pi)
{ {
struct hdmi_pll_info *pi = &pll->info; unsigned long fint, clkdco, clkout;
unsigned long refclk; unsigned long target_bitclk, target_clkdco;
u32 mf; unsigned long min_dco;
unsigned n, m, mf, m2, sd;
unsigned long clkin;
const struct dss_pll_hw *hw = pll->pll.hw;
/* use our funky units */ clkin = clk_get_rate(pll->pll.clkin);
clkin /= 10000;
/* DSSDBG("clkin %lu, target tmds %lu\n", clkin, target_tmds);
* Input clock is predivided by N + 1
* out put of which is reference clk
*/
pi->regn = HDMI_DEFAULT_REGN; target_bitclk = target_tmds * 10;
refclk = clkin / pi->regn; /* Fint */
n = DIV_ROUND_UP(clkin, hw->fint_max);
fint = clkin / n;
/* temorary hack to make sure DCO freq isn't calculated too low */ /* adjust m2 so that the clkdco will be high enough */
if (pll_feat->bound_dcofreq && phy <= 65000) min_dco = roundup(hw->clkdco_min, fint);
pi->regm2 = 3; m2 = DIV_ROUND_UP(min_dco, target_bitclk);
else if (m2 == 0)
pi->regm2 = HDMI_DEFAULT_REGM2; m2 = 1;
/*
* multiplier is pixel_clk/ref_clk
* Multiplying by 100 to avoid fractional part removal
*/
pi->regm = phy * pi->regm2 / refclk;
/*
* fractional multiplier is remainder of the difference between
* multiplier and actual phy(required pixel clock thus should be
* multiplied by 2^18(262144) divided by the reference clock
*/
mf = (phy - pi->regm / pi->regm2 * refclk) * 262144;
pi->regmf = pi->regm2 * mf / refclk;
/*
* Dcofreq should be set to 1 if required pixel clock
* is greater than 1000MHz
*/
pi->dcofreq = phy > 1000 * 100;
pi->regsd = ((pi->regm * clkin / 10) / (pi->regn * 250) + 5) / 10;
/* Set the reference clock to sysclk reference */
pi->refsel = HDMI_REFSEL_SYSCLK;
DSSDBG("M = %d Mf = %d\n", pi->regm, pi->regmf);
DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd);
}
target_clkdco = target_bitclk * m2;
m = target_clkdco / fint;
static int hdmi_pll_config(struct hdmi_pll_data *pll) clkdco = fint * m;
{
u32 r;
struct hdmi_pll_info *fmt = &pll->info;
/* PLL start always use manual mode */ /* adjust clkdco with fractional mf */
REG_FLD_MOD(pll->base, PLLCTRL_PLL_CONTROL, 0x0, 0, 0); if (WARN_ON(target_clkdco - clkdco > fint))
mf = 0;
r = hdmi_read_reg(pll->base, PLLCTRL_CFG1);
r = FLD_MOD(r, fmt->regm, 20, 9); /* CFG1_PLL_REGM */
r = FLD_MOD(r, fmt->regn - 1, 8, 1); /* CFG1_PLL_REGN */
hdmi_write_reg(pll->base, PLLCTRL_CFG1, r);
r = hdmi_read_reg(pll->base, PLLCTRL_CFG2);
r = FLD_MOD(r, 0x0, 12, 12); /* PLL_HIGHFREQ divide by 2 */
r = FLD_MOD(r, 0x1, 13, 13); /* PLL_REFEN */
r = FLD_MOD(r, 0x0, 14, 14); /* PHY_CLKINEN de-assert during locking */
r = FLD_MOD(r, fmt->refsel, 22, 21); /* REFSEL */
if (fmt->dcofreq)
r = FLD_MOD(r, 0x4, 3, 1); /* 1000MHz and 2000MHz */
else else
r = FLD_MOD(r, 0x2, 3, 1); /* 500MHz and 1000MHz */ mf = (u32)div_u64(262144ull * (target_clkdco - clkdco), fint);
hdmi_write_reg(pll->base, PLLCTRL_CFG2, r);
REG_FLD_MOD(pll->base, PLLCTRL_CFG3, fmt->regsd, 17, 10);
r = hdmi_read_reg(pll->base, PLLCTRL_CFG4); if (mf > 0)
r = FLD_MOD(r, fmt->regm2, 24, 18); clkdco += (u32)div_u64((u64)mf * fint, 262144);
r = FLD_MOD(r, fmt->regmf, 17, 0);
hdmi_write_reg(pll->base, PLLCTRL_CFG4, r);
/* go now */ clkout = clkdco / m2;
REG_FLD_MOD(pll->base, PLLCTRL_PLL_GO, 0x1, 0, 0);
/* wait for bit change */ /* sigma-delta */
if (hdmi_wait_for_bit_change(pll->base, PLLCTRL_PLL_GO, sd = DIV_ROUND_UP(fint * m, 250000000);
0, 0, 0) != 0) {
DSSERR("PLL GO bit not clearing\n");
return -ETIMEDOUT;
}
/* Wait till the lock bit is set in PLL status */ DSSDBG("N = %u, M = %u, M.f = %u, M2 = %u, SD = %u\n",
if (hdmi_wait_for_bit_change(pll->base, n, m, mf, m2, sd);
PLLCTRL_PLL_STATUS, 1, 1, 1) != 1) { DSSDBG("Fint %lu, clkdco %lu, clkout %lu\n", fint, clkdco, clkout);
DSSERR("cannot lock PLL\n");
DSSERR("CFG1 0x%x\n",
hdmi_read_reg(pll->base, PLLCTRL_CFG1));
DSSERR("CFG2 0x%x\n",
hdmi_read_reg(pll->base, PLLCTRL_CFG2));
DSSERR("CFG4 0x%x\n",
hdmi_read_reg(pll->base, PLLCTRL_CFG4));
return -ETIMEDOUT;
}
DSSDBG("PLL locked!\n"); pi->n = n;
pi->m = m;
pi->mf = mf;
pi->mX[0] = m2;
pi->sd = sd;
return 0; pi->fint = fint;
pi->clkdco = clkdco;
pi->clkout[0] = clkout;
} }
static int hdmi_pll_reset(struct hdmi_pll_data *pll) static int hdmi_pll_enable(struct dss_pll *dsspll)
{
/* SYSRESET controlled by power FSM */
REG_FLD_MOD(pll->base, PLLCTRL_PLL_CONTROL, pll_feat->sys_reset, 3, 3);
/* READ 0x0 reset is in progress */
if (hdmi_wait_for_bit_change(pll->base, PLLCTRL_PLL_STATUS, 0, 0, 1)
!= 1) {
DSSERR("Failed to sysreset PLL\n");
return -ETIMEDOUT;
}
return 0;
}
int hdmi_pll_enable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp)
{ {
struct hdmi_pll_data *pll = container_of(dsspll, struct hdmi_pll_data, pll);
struct hdmi_wp_data *wp = pll->wp;
u16 r = 0; u16 r = 0;
r = hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF);
if (r)
return r;
r = hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_BOTHON_ALLCLKS); r = hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_BOTHON_ALLCLKS);
if (r) if (r)
return r; return r;
r = hdmi_pll_reset(pll);
if (r)
return r;
r = hdmi_pll_config(pll);
if (r)
return r;
return 0; return 0;
} }
void hdmi_pll_disable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp) static void hdmi_pll_disable(struct dss_pll *dsspll)
{ {
struct hdmi_pll_data *pll = container_of(dsspll, struct hdmi_pll_data, pll);
struct hdmi_wp_data *wp = pll->wp;
hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF); hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF);
} }
static const struct hdmi_pll_features omap44xx_pll_feats = { static const struct dss_pll_ops dsi_pll_ops = {
.sys_reset = false, .enable = hdmi_pll_enable,
.bound_dcofreq = false, .disable = hdmi_pll_disable,
.fint_min = 500000, .set_config = dss_pll_write_config_type_b,
.fint_max = 2500000,
.regm_max = 4095,
.dcofreq_low_min = 500000000,
.dcofreq_low_max = 1000000000,
.dcofreq_high_min = 1000000000,
.dcofreq_high_max = 2000000000,
}; };
static const struct hdmi_pll_features omap54xx_pll_feats = { static const struct dss_pll_hw dss_omap4_hdmi_pll_hw = {
.sys_reset = true, .n_max = 255,
.bound_dcofreq = true, .m_min = 20,
.fint_min = 620000, .m_max = 4095,
.fint_max = 2500000, .mX_max = 127,
.regm_max = 2046, .fint_min = 500000,
.dcofreq_low_min = 750000000, .fint_max = 2500000,
.dcofreq_low_max = 1500000000, .clkdco_max = 1800000000,
.dcofreq_high_min = 1250000000,
.dcofreq_high_max = 2500000000UL, .clkdco_min = 500000000,
.clkdco_low = 1000000000,
.clkdco_max = 2000000000,
.n_msb = 8,
.n_lsb = 1,
.m_msb = 20,
.m_lsb = 9,
.mX_msb[0] = 24,
.mX_lsb[0] = 18,
.has_selfreqdco = true,
}; };
static int hdmi_pll_init_features(struct platform_device *pdev) static const struct dss_pll_hw dss_omap5_hdmi_pll_hw = {
.n_max = 255,
.m_min = 20,
.m_max = 2045,
.mX_max = 127,
.fint_min = 620000,
.fint_max = 2500000,
.clkdco_max = 1800000000,
.clkdco_min = 750000000,
.clkdco_low = 1500000000,
.clkdco_max = 2500000000UL,
.n_msb = 8,
.n_lsb = 1,
.m_msb = 20,
.m_lsb = 9,
.mX_msb[0] = 24,
.mX_lsb[0] = 18,
.has_selfreqdco = true,
.has_refsel = true,
};
static int dsi_init_pll_data(struct platform_device *pdev, struct hdmi_pll_data *hpll)
{ {
struct hdmi_pll_features *dst; struct dss_pll *pll = &hpll->pll;
const struct hdmi_pll_features *src; struct clk *clk;
int r;
dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL); clk = devm_clk_get(&pdev->dev, "sys_clk");
if (!dst) { if (IS_ERR(clk)) {
dev_err(&pdev->dev, "Failed to allocate HDMI PHY Features\n"); DSSERR("can't get sys_clk\n");
return -ENOMEM; return PTR_ERR(clk);
} }
pll->name = "hdmi";
pll->base = hpll->base;
pll->clkin = clk;
switch (omapdss_get_version()) { switch (omapdss_get_version()) {
case OMAPDSS_VER_OMAP4430_ES1: case OMAPDSS_VER_OMAP4430_ES1:
case OMAPDSS_VER_OMAP4430_ES2: case OMAPDSS_VER_OMAP4430_ES2:
case OMAPDSS_VER_OMAP4: case OMAPDSS_VER_OMAP4:
src = &omap44xx_pll_feats; pll->hw = &dss_omap4_hdmi_pll_hw;
break; break;
case OMAPDSS_VER_OMAP5: case OMAPDSS_VER_OMAP5:
src = &omap54xx_pll_feats; pll->hw = &dss_omap5_hdmi_pll_hw;
break; break;
default: default:
return -ENODEV; return -ENODEV;
} }
memcpy(dst, src, sizeof(*dst)); pll->ops = &dsi_pll_ops;
pll_feat = dst;
r = dss_pll_register(pll);
if (r)
return r;
return 0; return 0;
} }
int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll) int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll,
struct hdmi_wp_data *wp)
{ {
int r; int r;
struct resource *res; struct resource *res;
r = hdmi_pll_init_features(pdev); pll->wp = wp;
if (r)
return r;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll"); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll");
if (!res) { if (!res) {
...@@ -286,5 +234,18 @@ int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll) ...@@ -286,5 +234,18 @@ int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll)
return PTR_ERR(pll->base); return PTR_ERR(pll->base);
} }
r = dsi_init_pll_data(pdev, pll);
if (r) {
DSSERR("failed to init HDMI PLL\n");
return r;
}
return 0; return 0;
} }
void hdmi_pll_uninit(struct hdmi_pll_data *hpll)
{
struct dss_pll *pll = &hpll->pll;
dss_pll_unregister(pll);
}
...@@ -185,7 +185,6 @@ void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt, ...@@ -185,7 +185,6 @@ void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt,
timings->interlace = param->timings.interlace; timings->interlace = param->timings.interlace;
} }
#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) || defined(CONFIG_OMAP5_DSS_HDMI_AUDIO)
void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp, void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp,
struct hdmi_audio_format *aud_fmt) struct hdmi_audio_format *aud_fmt)
{ {
...@@ -194,8 +193,12 @@ void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp, ...@@ -194,8 +193,12 @@ void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp,
DSSDBG("Enter hdmi_wp_audio_config_format\n"); DSSDBG("Enter hdmi_wp_audio_config_format\n");
r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CFG); r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CFG);
r = FLD_MOD(r, aud_fmt->stereo_channels, 26, 24); if (omapdss_get_version() == OMAPDSS_VER_OMAP4430_ES1 ||
r = FLD_MOD(r, aud_fmt->active_chnnls_msk, 23, 16); omapdss_get_version() == OMAPDSS_VER_OMAP4430_ES2 ||
omapdss_get_version() == OMAPDSS_VER_OMAP4) {
r = FLD_MOD(r, aud_fmt->stereo_channels, 26, 24);
r = FLD_MOD(r, aud_fmt->active_chnnls_msk, 23, 16);
}
r = FLD_MOD(r, aud_fmt->en_sig_blk_strt_end, 5, 5); r = FLD_MOD(r, aud_fmt->en_sig_blk_strt_end, 5, 5);
r = FLD_MOD(r, aud_fmt->type, 4, 4); r = FLD_MOD(r, aud_fmt->type, 4, 4);
r = FLD_MOD(r, aud_fmt->justification, 3, 3); r = FLD_MOD(r, aud_fmt->justification, 3, 3);
...@@ -236,7 +239,6 @@ int hdmi_wp_audio_core_req_enable(struct hdmi_wp_data *wp, bool enable) ...@@ -236,7 +239,6 @@ int hdmi_wp_audio_core_req_enable(struct hdmi_wp_data *wp, bool enable)
return 0; return 0;
} }
#endif
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)
{ {
...@@ -247,6 +249,7 @@ int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp) ...@@ -247,6 +249,7 @@ int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp)
DSSERR("can't get WP mem resource\n"); DSSERR("can't get WP mem resource\n");
return -EINVAL; return -EINVAL;
} }
wp->phys_base = res->start;
wp->base = devm_ioremap_resource(&pdev->dev, res); wp->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(wp->base)) { if (IS_ERR(wp->base)) {
...@@ -256,3 +259,8 @@ int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp) ...@@ -256,3 +259,8 @@ int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp)
return 0; return 0;
} }
phys_addr_t hdmi_wp_get_audio_dma_addr(struct hdmi_wp_data *wp)
{
return wp->phys_base + HDMI_WP_AUDIO_DATA;
}
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/of.h>
#include <video/omapdss.h> #include <video/omapdss.h>
...@@ -131,18 +132,30 @@ struct omap_dss_device *omap_dss_find_output(const char *name) ...@@ -131,18 +132,30 @@ struct omap_dss_device *omap_dss_find_output(const char *name)
} }
EXPORT_SYMBOL(omap_dss_find_output); EXPORT_SYMBOL(omap_dss_find_output);
struct omap_dss_device *omap_dss_find_output_by_node(struct device_node *node) struct omap_dss_device *omap_dss_find_output_by_port_node(struct device_node *port)
{ {
struct device_node *src_node;
struct omap_dss_device *out; struct omap_dss_device *out;
u32 reg;
src_node = dss_of_port_get_parent_device(port);
if (!src_node)
return NULL;
reg = dss_of_port_get_port_number(port);
list_for_each_entry(out, &output_list, list) { list_for_each_entry(out, &output_list, list) {
if (out->dev->of_node == node) if (out->dev->of_node == src_node && out->port_num == reg) {
of_node_put(src_node);
return omap_dss_get_device(out); return omap_dss_get_device(out);
}
} }
of_node_put(src_node);
return NULL; return NULL;
} }
EXPORT_SYMBOL(omap_dss_find_output_by_node); EXPORT_SYMBOL(omap_dss_find_output_by_port_node);
struct omap_dss_device *omapdss_find_output_from_display(struct omap_dss_device *dssdev) struct omap_dss_device *omapdss_find_output_from_display(struct omap_dss_device *dssdev)
{ {
......
此差异已折叠。
...@@ -425,7 +425,7 @@ int __init sdi_init_port(struct platform_device *pdev, struct device_node *port) ...@@ -425,7 +425,7 @@ int __init sdi_init_port(struct platform_device *pdev, struct device_node *port)
return r; return r;
} }
void __exit sdi_uninit_port(void) void __exit sdi_uninit_port(struct device_node *port)
{ {
if (!sdi.port_initialized) if (!sdi.port_initialized)
return; return;
......
...@@ -26,6 +26,8 @@ ...@@ -26,6 +26,8 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_data/simplefb.h> #include <linux/platform_data/simplefb.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/clk-provider.h>
#include <linux/of_platform.h>
static struct fb_fix_screeninfo simplefb_fix = { static struct fb_fix_screeninfo simplefb_fix = {
.id = "simple", .id = "simple",
...@@ -41,6 +43,8 @@ static struct fb_var_screeninfo simplefb_var = { ...@@ -41,6 +43,8 @@ static struct fb_var_screeninfo simplefb_var = {
.vmode = FB_VMODE_NONINTERLACED, .vmode = FB_VMODE_NONINTERLACED,
}; };
#define PSEUDO_PALETTE_SIZE 16
static int simplefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, static int simplefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
u_int transp, struct fb_info *info) u_int transp, struct fb_info *info)
{ {
...@@ -50,7 +54,7 @@ static int simplefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, ...@@ -50,7 +54,7 @@ static int simplefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
u32 cb = blue >> (16 - info->var.blue.length); u32 cb = blue >> (16 - info->var.blue.length);
u32 value; u32 value;
if (regno >= 16) if (regno >= PSEUDO_PALETTE_SIZE)
return -EINVAL; return -EINVAL;
value = (cr << info->var.red.offset) | value = (cr << info->var.red.offset) |
...@@ -163,11 +167,113 @@ static int simplefb_parse_pd(struct platform_device *pdev, ...@@ -163,11 +167,113 @@ static int simplefb_parse_pd(struct platform_device *pdev,
return 0; return 0;
} }
struct simplefb_par {
u32 palette[PSEUDO_PALETTE_SIZE];
#if defined CONFIG_OF && defined CONFIG_COMMON_CLK
int clk_count;
struct clk **clks;
#endif
};
#if defined CONFIG_OF && defined CONFIG_COMMON_CLK
/*
* Clock handling code.
*
* Here we handle the clocks property of our "simple-framebuffer" dt node.
* This is necessary so that we can make sure that any clocks needed by
* the display engine that the bootloader set up for us (and for which it
* provided a simplefb dt node), stay up, for the life of the simplefb
* driver.
*
* When the driver unloads, we cleanly disable, and then release the clocks.
*
* We only complain about errors here, no action is taken as the most likely
* error can only happen due to a mismatch between the bootloader which set
* up simplefb, and the clock definitions in the device tree. Chances are
* that there are no adverse effects, and if there are, a clean teardown of
* the fb probe will not help us much either. So just complain and carry on,
* and hope that the user actually gets a working fb at the end of things.
*/
static int simplefb_clocks_init(struct simplefb_par *par,
struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct clk *clock;
int i, ret;
if (dev_get_platdata(&pdev->dev) || !np)
return 0;
par->clk_count = of_clk_get_parent_count(np);
if (par->clk_count <= 0)
return 0;
par->clks = kcalloc(par->clk_count, sizeof(struct clk *), GFP_KERNEL);
if (!par->clks)
return -ENOMEM;
for (i = 0; i < par->clk_count; i++) {
clock = of_clk_get(np, i);
if (IS_ERR(clock)) {
if (PTR_ERR(clock) == -EPROBE_DEFER) {
while (--i >= 0) {
if (par->clks[i])
clk_put(par->clks[i]);
}
kfree(par->clks);
return -EPROBE_DEFER;
}
dev_err(&pdev->dev, "%s: clock %d not found: %ld\n",
__func__, i, PTR_ERR(clock));
continue;
}
par->clks[i] = clock;
}
for (i = 0; i < par->clk_count; i++) {
if (par->clks[i]) {
ret = clk_prepare_enable(par->clks[i]);
if (ret) {
dev_err(&pdev->dev,
"%s: failed to enable clock %d: %d\n",
__func__, i, ret);
clk_put(par->clks[i]);
par->clks[i] = NULL;
}
}
}
return 0;
}
static void simplefb_clocks_destroy(struct simplefb_par *par)
{
int i;
if (!par->clks)
return;
for (i = 0; i < par->clk_count; i++) {
if (par->clks[i]) {
clk_disable_unprepare(par->clks[i]);
clk_put(par->clks[i]);
}
}
kfree(par->clks);
}
#else
static int simplefb_clocks_init(struct simplefb_par *par,
struct platform_device *pdev) { return 0; }
static void simplefb_clocks_destroy(struct simplefb_par *par) { }
#endif
static int simplefb_probe(struct platform_device *pdev) static int simplefb_probe(struct platform_device *pdev)
{ {
int ret; int ret;
struct simplefb_params params; struct simplefb_params params;
struct fb_info *info; struct fb_info *info;
struct simplefb_par *par;
struct resource *mem; struct resource *mem;
if (fb_get_options("simplefb", NULL)) if (fb_get_options("simplefb", NULL))
...@@ -188,11 +294,13 @@ static int simplefb_probe(struct platform_device *pdev) ...@@ -188,11 +294,13 @@ static int simplefb_probe(struct platform_device *pdev)
return -EINVAL; return -EINVAL;
} }
info = framebuffer_alloc(sizeof(u32) * 16, &pdev->dev); info = framebuffer_alloc(sizeof(struct simplefb_par), &pdev->dev);
if (!info) if (!info)
return -ENOMEM; return -ENOMEM;
platform_set_drvdata(pdev, info); platform_set_drvdata(pdev, info);
par = info->par;
info->fix = simplefb_fix; info->fix = simplefb_fix;
info->fix.smem_start = mem->start; info->fix.smem_start = mem->start;
info->fix.smem_len = resource_size(mem); info->fix.smem_len = resource_size(mem);
...@@ -211,8 +319,8 @@ static int simplefb_probe(struct platform_device *pdev) ...@@ -211,8 +319,8 @@ static int simplefb_probe(struct platform_device *pdev)
info->apertures = alloc_apertures(1); info->apertures = alloc_apertures(1);
if (!info->apertures) { if (!info->apertures) {
framebuffer_release(info); ret = -ENOMEM;
return -ENOMEM; goto error_fb_release;
} }
info->apertures->ranges[0].base = info->fix.smem_start; info->apertures->ranges[0].base = info->fix.smem_start;
info->apertures->ranges[0].size = info->fix.smem_len; info->apertures->ranges[0].size = info->fix.smem_len;
...@@ -222,10 +330,14 @@ static int simplefb_probe(struct platform_device *pdev) ...@@ -222,10 +330,14 @@ static int simplefb_probe(struct platform_device *pdev)
info->screen_base = ioremap_wc(info->fix.smem_start, info->screen_base = ioremap_wc(info->fix.smem_start,
info->fix.smem_len); info->fix.smem_len);
if (!info->screen_base) { if (!info->screen_base) {
framebuffer_release(info); ret = -ENOMEM;
return -ENODEV; goto error_fb_release;
} }
info->pseudo_palette = (void *)(info + 1); info->pseudo_palette = par->palette;
ret = simplefb_clocks_init(par, pdev);
if (ret < 0)
goto error_unmap;
dev_info(&pdev->dev, "framebuffer at 0x%lx, 0x%x bytes, mapped to 0x%p\n", dev_info(&pdev->dev, "framebuffer at 0x%lx, 0x%x bytes, mapped to 0x%p\n",
info->fix.smem_start, info->fix.smem_len, info->fix.smem_start, info->fix.smem_len,
...@@ -238,21 +350,29 @@ static int simplefb_probe(struct platform_device *pdev) ...@@ -238,21 +350,29 @@ static int simplefb_probe(struct platform_device *pdev)
ret = register_framebuffer(info); ret = register_framebuffer(info);
if (ret < 0) { if (ret < 0) {
dev_err(&pdev->dev, "Unable to register simplefb: %d\n", ret); dev_err(&pdev->dev, "Unable to register simplefb: %d\n", ret);
iounmap(info->screen_base); goto error_clocks;
framebuffer_release(info);
return ret;
} }
dev_info(&pdev->dev, "fb%d: simplefb registered!\n", info->node); dev_info(&pdev->dev, "fb%d: simplefb registered!\n", info->node);
return 0; return 0;
error_clocks:
simplefb_clocks_destroy(par);
error_unmap:
iounmap(info->screen_base);
error_fb_release:
framebuffer_release(info);
return ret;
} }
static int simplefb_remove(struct platform_device *pdev) static int simplefb_remove(struct platform_device *pdev)
{ {
struct fb_info *info = platform_get_drvdata(pdev); struct fb_info *info = platform_get_drvdata(pdev);
struct simplefb_par *par = info->par;
unregister_framebuffer(info); unregister_framebuffer(info);
simplefb_clocks_destroy(par);
framebuffer_release(info); framebuffer_release(info);
return 0; return 0;
...@@ -273,7 +393,27 @@ static struct platform_driver simplefb_driver = { ...@@ -273,7 +393,27 @@ static struct platform_driver simplefb_driver = {
.probe = simplefb_probe, .probe = simplefb_probe,
.remove = simplefb_remove, .remove = simplefb_remove,
}; };
module_platform_driver(simplefb_driver);
static int __init simplefb_init(void)
{
int ret;
struct device_node *np;
ret = platform_driver_register(&simplefb_driver);
if (ret)
return ret;
if (IS_ENABLED(CONFIG_OF) && of_chosen) {
for_each_child_of_node(of_chosen, np) {
if (of_device_is_compatible(np, "simple-framebuffer"))
of_platform_device_create(np, NULL, NULL);
}
}
return 0;
}
fs_initcall(simplefb_init);
MODULE_AUTHOR("Stephen Warren <swarren@wwwdotorg.org>"); MODULE_AUTHOR("Stephen Warren <swarren@wwwdotorg.org>");
MODULE_DESCRIPTION("Simple framebuffer driver"); MODULE_DESCRIPTION("Simple framebuffer driver");
......
...@@ -105,8 +105,6 @@ static inline struct device_node *of_node_get(struct device_node *node) ...@@ -105,8 +105,6 @@ static inline struct device_node *of_node_get(struct device_node *node)
static inline void of_node_put(struct device_node *node) { } static inline void of_node_put(struct device_node *node) { }
#endif /* !CONFIG_OF_DYNAMIC */ #endif /* !CONFIG_OF_DYNAMIC */
#ifdef CONFIG_OF
/* Pointer for first entry in chain of all nodes. */ /* Pointer for first entry in chain of all nodes. */
extern struct device_node *of_allnodes; extern struct device_node *of_allnodes;
extern struct device_node *of_chosen; extern struct device_node *of_chosen;
...@@ -114,6 +112,7 @@ extern struct device_node *of_aliases; ...@@ -114,6 +112,7 @@ extern struct device_node *of_aliases;
extern struct device_node *of_stdout; extern struct device_node *of_stdout;
extern raw_spinlock_t devtree_lock; extern raw_spinlock_t devtree_lock;
#ifdef CONFIG_OF
static inline bool of_have_populated_dt(void) static inline bool of_have_populated_dt(void)
{ {
return of_allnodes != NULL; return of_allnodes != NULL;
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册