mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-26 08:50:54 +07:00
fbdev changes for 3.19
* support for mx6sl and mx6sx * OMAP HDMI audio rewrite to make it finally work * OMAP video PLL work to prepare for new DRA7xx SoCs * simplefb DT related improvements -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJUiZ3aAAoJEPo9qoy8lh71I4gP/0P0H7DtqwSRGWVDenVYC4o1 IoRJgRBSu16gg9h1yEbluGIB0S/F+0vvgJLv83fXPIFYCApjeIyola60wzTxsCQO 5+DY8IbioAiYCAC4brPbE17PQZhkqomVZy7Eo/WW8Bp7NRwhIVGgstjfKIKarRmR l7Zu7ciRt7A1677P8Te09w3hzWfvRNOCYi/lbSbHHeItpAfOqBQLI6WYh0WYFgbW oOqplfJKQDW67mj+DmnR8ep+CwN6/+AvmialkwiPKKBjE578zmTJuRXr/ZZMgqmY WiqC3O3yoTaDn9ReUw1CBmeYbWfhjdDotydTc0eUD+Z3cGIKlBh3coprpOEILuuU FCsbBWQGP2FtYPfvl0R80+VHLRhDxFXV0hcxocyvNzK78AfKrTKBMYTdPh/i+0M/ +pA70thjlKpqZgBK6ukyMnB6KxiB9tOFdFx7PRXby4VgRGHqeYNRlvYPcYOPsgb2 xRMIxCWhJHqZzNlv+bC6R4T8UTOIT4HoWthF0yN7SYrVujX0+1ky8Zz37jcTFnnS aNQ8MQL+6Uy1pa0v2c4oGH0qNVCWpsAXMtFBB1VkNzQg1vyuJHd3lgWYND33+3Uo C08lqzC3FZeA70g5iOhoP5IaW1JdQOe4EfDPU+ZjBQFB0Mgy025Z9dsAUcb08/2C s/ZXcRvzXMzpBSflsUzf =VAZB -----END PGP SIGNATURE----- Merge tag 'fbdev-3.19' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux Pull fbdev updates from Tomi Valkeinen: - support for mx6sl and mx6sx - OMAP HDMI audio rewrite to make it finally work - OMAP video PLL work to prepare for new DRA7xx SoCs - simplefb DT related improvements * tag 'fbdev-3.19' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux: (81 commits) video: uvesafb: Deletion of an unnecessary check before the function call "platform_device_put" video: fbdev-VIA: Deletion of an unnecessary check before the function call "framebuffer_release" video: fbdev-MMP: Deletion of an unnecessary check before the function call "mmp_unregister_path" video: mx3fb: Deletion of an unnecessary check before the function call "backlight_device_unregister" video: fbdev-OMAP2: Deletion of unnecessary checks before the function call "i2c_put_adapter" video: fbdev-SIS: Deletion of unnecessary checks before the function call "pci_dev_put" video: smscufx: Deletion of unnecessary checks before the function call "vfree" video: udlfb: Deletion of unnecessary checks before the function call "vfree" video: uvesafb: Deletion of an unnecessary check before the function call "uvesafb_free" video: fbdev-LCDC: Deletion of an unnecessary check before the function call "vfree" video: fbdev: arkfb: suppress build warning video: fbdev: s3fb: suppress build warning video: fbdev: vt8623fb: suppress build warning OMAPDSS: hdmi5: Fix bit field for IEC958_AES2_CON_SOURCE OMAPDSS: hdmi: Remove __exit qualifier from hdmi_uninit_output() OMAPDSS: hdmi5: Change hdmi_wp idlemode to to no_idle for audio playback OMAPDSS: Remove all references to obsolete HDMI audio callbacks ASoC: omap: Remove obsolete HDMI audio code and Kconfig options OMAPDSS: hdmi5: Register ASoC platform device for omap hdmi audio OMAPDSS: hdmi5: Remove callbacks for the old ASoC DAI driver ...
This commit is contained in:
commit
413fd0e3fb
@ -0,0 +1,33 @@
|
||||
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";
|
||||
};
|
||||
};
|
@ -1,8 +1,40 @@
|
||||
Simple Framebuffer
|
||||
|
||||
A simple frame-buffer describes a raw memory region that may be rendered to,
|
||||
with the assumption that the display hardware has already been set up to scan
|
||||
out from that buffer.
|
||||
A simple frame-buffer describes a frame-buffer setup by firmware or
|
||||
the bootloader, with the assumption that the display hardware has already
|
||||
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:
|
||||
- compatible: "simple-framebuffer"
|
||||
@ -14,13 +46,41 @@ Required properties:
|
||||
- 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).
|
||||
|
||||
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:
|
||||
|
||||
framebuffer {
|
||||
aliases {
|
||||
display0 = &lcdc0;
|
||||
}
|
||||
|
||||
chosen {
|
||||
framebuffer0: framebuffer@1d385000 {
|
||||
compatible = "simple-framebuffer";
|
||||
reg = <0x1d385000 (1600 * 1200 * 2)>;
|
||||
width = <1600>;
|
||||
height = <1200>;
|
||||
stride = <(1600 * 2)>;
|
||||
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.
|
||||
|
@ -8586,6 +8586,14 @@ F: drivers/media/usb/siano/
|
||||
F: drivers/media/usb/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
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Orphan
|
||||
|
@ -3624,7 +3624,7 @@ static int __init fb_console_init(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
module_init(fb_console_init);
|
||||
fs_initcall(fb_console_init);
|
||||
|
||||
#ifdef MODULE
|
||||
|
||||
|
@ -2408,7 +2408,7 @@ config FB_JZ4740
|
||||
|
||||
config FB_MXS
|
||||
tristate "MXS LCD framebuffer support"
|
||||
depends on FB && ARCH_MXS
|
||||
depends on FB && (ARCH_MXS || ARCH_MXC)
|
||||
select FB_CFB_FILLRECT
|
||||
select FB_CFB_COPYAREA
|
||||
select FB_CFB_IMAGEBLIT
|
||||
|
@ -27,7 +27,6 @@
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/hardirq.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_graph.h>
|
||||
|
@ -1016,7 +1016,7 @@ static int ark_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
|
||||
pcibios_bus_to_resource(dev->bus, &vga_res, &bus_reg);
|
||||
|
||||
par->state.vgabase = (void __iomem *) vga_res.start;
|
||||
par->state.vgabase = (void __iomem *) (unsigned long) vga_res.start;
|
||||
|
||||
/* FIXME get memsize */
|
||||
regval = vga_rseq(par->state.vgabase, 0x10);
|
||||
|
@ -223,10 +223,10 @@ struct mmp_path *mmp_register_path(struct mmp_path_info *info)
|
||||
EXPORT_SYMBOL_GPL(mmp_register_path);
|
||||
|
||||
/*
|
||||
* mmp_unregister_path - unregister and destory path
|
||||
* @p: path to be destoried.
|
||||
* mmp_unregister_path - unregister and destroy path
|
||||
* @p: path to be destroyed.
|
||||
*
|
||||
* this function registers path and destorys it.
|
||||
* this function registers path and destroys it.
|
||||
*/
|
||||
void mmp_unregister_path(struct mmp_path *path)
|
||||
{
|
||||
|
@ -441,8 +441,7 @@ static void path_deinit(struct mmphw_path_plat *path_plat)
|
||||
if (!path_plat)
|
||||
return;
|
||||
|
||||
if (path_plat->path)
|
||||
mmp_unregister_path(path_plat->path);
|
||||
mmp_unregister_path(path_plat->path);
|
||||
}
|
||||
|
||||
static int mmphw_probe(struct platform_device *pdev)
|
||||
|
@ -334,8 +334,7 @@ static void mx3fb_init_backlight(struct mx3fb_data *fbd)
|
||||
|
||||
static void mx3fb_exit_backlight(struct mx3fb_data *fbd)
|
||||
{
|
||||
if (fbd->bl)
|
||||
backlight_device_unregister(fbd->bl);
|
||||
backlight_device_unregister(fbd->bl);
|
||||
}
|
||||
|
||||
static void mx3fb_dma_done(void *);
|
||||
|
@ -172,6 +172,8 @@ struct mxsfb_info {
|
||||
struct fb_info fb_info;
|
||||
struct platform_device *pdev;
|
||||
struct clk *clk;
|
||||
struct clk *clk_axi;
|
||||
struct clk *clk_disp_axi;
|
||||
void __iomem *base; /* registers */
|
||||
unsigned allocated_size;
|
||||
int enabled;
|
||||
@ -331,6 +333,11 @@ static void mxsfb_enable_controller(struct fb_info *fb_info)
|
||||
}
|
||||
}
|
||||
|
||||
if (host->clk_axi)
|
||||
clk_prepare_enable(host->clk_axi);
|
||||
|
||||
if (host->clk_disp_axi)
|
||||
clk_prepare_enable(host->clk_disp_axi);
|
||||
clk_prepare_enable(host->clk);
|
||||
clk_set_rate(host->clk, PICOS2KHZ(fb_info->var.pixclock) * 1000U);
|
||||
|
||||
@ -374,6 +381,10 @@ static void mxsfb_disable_controller(struct fb_info *fb_info)
|
||||
writel(reg & ~VDCTRL4_SYNC_SIGNALS_ON, host->base + LCDC_VDCTRL4);
|
||||
|
||||
clk_disable_unprepare(host->clk);
|
||||
if (host->clk_disp_axi)
|
||||
clk_disable_unprepare(host->clk_disp_axi);
|
||||
if (host->clk_axi)
|
||||
clk_disable_unprepare(host->clk_axi);
|
||||
|
||||
host->enabled = 0;
|
||||
|
||||
@ -867,6 +878,14 @@ static int mxsfb_probe(struct platform_device *pdev)
|
||||
goto fb_release;
|
||||
}
|
||||
|
||||
host->clk_axi = devm_clk_get(&host->pdev->dev, "axi");
|
||||
if (IS_ERR(host->clk_axi))
|
||||
host->clk_axi = NULL;
|
||||
|
||||
host->clk_disp_axi = devm_clk_get(&host->pdev->dev, "disp_axi");
|
||||
if (IS_ERR(host->clk_disp_axi))
|
||||
host->clk_disp_axi = NULL;
|
||||
|
||||
host->reg_lcd = devm_regulator_get(&pdev->dev, "lcd");
|
||||
if (IS_ERR(host->reg_lcd))
|
||||
host->reg_lcd = NULL;
|
||||
|
@ -262,8 +262,7 @@ static int dvic_probe_pdata(struct platform_device *pdev)
|
||||
|
||||
in = omap_dss_find_output(pdata->source);
|
||||
if (in == NULL) {
|
||||
if (ddata->i2c_adapter)
|
||||
i2c_put_adapter(ddata->i2c_adapter);
|
||||
i2c_put_adapter(ddata->i2c_adapter);
|
||||
|
||||
dev_err(&pdev->dev, "Failed to find video source\n");
|
||||
return -EPROBE_DEFER;
|
||||
@ -352,8 +351,7 @@ static int dvic_probe(struct platform_device *pdev)
|
||||
err_reg:
|
||||
omap_dss_put_device(ddata->in);
|
||||
|
||||
if (ddata->i2c_adapter)
|
||||
i2c_put_adapter(ddata->i2c_adapter);
|
||||
i2c_put_adapter(ddata->i2c_adapter);
|
||||
|
||||
return r;
|
||||
}
|
||||
@ -371,8 +369,7 @@ static int __exit dvic_remove(struct platform_device *pdev)
|
||||
|
||||
omap_dss_put_device(in);
|
||||
|
||||
if (ddata->i2c_adapter)
|
||||
i2c_put_adapter(ddata->i2c_adapter);
|
||||
i2c_put_adapter(ddata->i2c_adapter);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -170,98 +170,6 @@ static bool hdmic_detect(struct omap_dss_device *dssdev)
|
||||
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)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
@ -296,13 +204,6 @@ static struct omap_dss_driver hdmic_driver = {
|
||||
.detect = hdmic_detect,
|
||||
.set_hdmi_mode = hdmic_set_hdmi_mode,
|
||||
.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)
|
||||
|
@ -249,6 +249,7 @@ static int tfp410_probe(struct platform_device *pdev)
|
||||
dssdev->output_type = OMAP_DISPLAY_TYPE_DVI;
|
||||
dssdev->owner = THIS_MODULE;
|
||||
dssdev->phy.dpi.data_lines = ddata->data_lines;
|
||||
dssdev->port_num = 1;
|
||||
|
||||
r = omapdss_register_output(dssdev);
|
||||
if (r) {
|
||||
|
@ -193,55 +193,6 @@ static bool tpd_detect(struct omap_dss_device *dssdev)
|
||||
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,
|
||||
const struct hdmi_avi_infoframe *avi)
|
||||
{
|
||||
@ -275,13 +226,6 @@ static const struct omapdss_hdmi_ops tpd_hdmi_ops = {
|
||||
.detect = tpd_detect,
|
||||
.set_infoframe = tpd_set_infoframe,
|
||||
.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)
|
||||
@ -409,6 +353,7 @@ static int tpd_probe(struct platform_device *pdev)
|
||||
dssdev->type = OMAP_DISPLAY_TYPE_HDMI;
|
||||
dssdev->output_type = OMAP_DISPLAY_TYPE_HDMI;
|
||||
dssdev->owner = THIS_MODULE;
|
||||
dssdev->port_num = 1;
|
||||
|
||||
in = ddata->in;
|
||||
|
||||
|
@ -74,9 +74,6 @@ config OMAP4_DSS_HDMI
|
||||
help
|
||||
HDMI support for OMAP4 based SoCs.
|
||||
|
||||
config OMAP4_DSS_HDMI_AUDIO
|
||||
bool
|
||||
|
||||
config OMAP5_DSS_HDMI
|
||||
bool "HDMI support for OMAP5"
|
||||
default n
|
||||
@ -86,10 +83,6 @@ config OMAP5_DSS_HDMI
|
||||
Definition Multimedia Interface. See http://www.hdmi.org/ for HDMI
|
||||
specification.
|
||||
|
||||
config OMAP5_DSS_HDMI_AUDIO
|
||||
depends on OMAP5_DSS_HDMI
|
||||
bool
|
||||
|
||||
config OMAP2_DSS_SDI
|
||||
bool "SDI support"
|
||||
default n
|
||||
|
@ -2,7 +2,7 @@ obj-$(CONFIG_OMAP2_DSS_INIT) += omapdss-boot-init.o
|
||||
obj-$(CONFIG_OMAP2_DSS) += omapdss.o
|
||||
# Core DSS files
|
||||
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
|
||||
omapdss-y += manager.o manager-sysfs.o overlay.o overlay-sysfs.o apply.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,
|
||||
|
||||
unsigned long dispc_fclk_rate(void)
|
||||
{
|
||||
struct platform_device *dsidev;
|
||||
struct dss_pll *pll;
|
||||
unsigned long r = 0;
|
||||
|
||||
switch (dss_get_dispc_clk_source()) {
|
||||
@ -3036,12 +3036,12 @@ unsigned long dispc_fclk_rate(void)
|
||||
r = dss_get_dispc_clk_rate();
|
||||
break;
|
||||
case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
|
||||
dsidev = dsi_get_dsidev_from_id(0);
|
||||
r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
|
||||
pll = dss_pll_find("dsi0");
|
||||
r = pll->cinfo.clkout[0];
|
||||
break;
|
||||
case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
|
||||
dsidev = dsi_get_dsidev_from_id(1);
|
||||
r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
|
||||
pll = dss_pll_find("dsi1");
|
||||
r = pll->cinfo.clkout[0];
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
@ -3053,7 +3053,7 @@ unsigned long dispc_fclk_rate(void)
|
||||
|
||||
unsigned long dispc_mgr_lclk_rate(enum omap_channel channel)
|
||||
{
|
||||
struct platform_device *dsidev;
|
||||
struct dss_pll *pll;
|
||||
int lcd;
|
||||
unsigned long r;
|
||||
u32 l;
|
||||
@ -3068,12 +3068,12 @@ unsigned long dispc_mgr_lclk_rate(enum omap_channel channel)
|
||||
r = dss_get_dispc_clk_rate();
|
||||
break;
|
||||
case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
|
||||
dsidev = dsi_get_dsidev_from_id(0);
|
||||
r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
|
||||
pll = dss_pll_find("dsi0");
|
||||
r = pll->cinfo.clkout[0];
|
||||
break;
|
||||
case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
|
||||
dsidev = dsi_get_dsidev_from_id(1);
|
||||
r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
|
||||
pll = dss_pll_find("dsi1");
|
||||
r = pll->cinfo.clkout[0];
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
|
@ -31,17 +31,20 @@
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
|
||||
#include "dss.h"
|
||||
#include "dss_features.h"
|
||||
|
||||
static struct {
|
||||
#define HSDIV_DISPC 0
|
||||
|
||||
struct dpi_data {
|
||||
struct platform_device *pdev;
|
||||
|
||||
struct regulator *vdds_dsi_reg;
|
||||
struct platform_device *dsidev;
|
||||
struct dss_pll *pll;
|
||||
|
||||
struct mutex lock;
|
||||
|
||||
@ -52,9 +55,20 @@ static struct {
|
||||
struct omap_dss_device output;
|
||||
|
||||
bool port_initialized;
|
||||
} dpi;
|
||||
};
|
||||
|
||||
static struct platform_device *dpi_get_dsidev(enum omap_channel channel)
|
||||
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 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
|
||||
@ -75,9 +89,9 @@ static struct platform_device *dpi_get_dsidev(enum omap_channel channel)
|
||||
case OMAPDSS_VER_OMAP4:
|
||||
switch (channel) {
|
||||
case OMAP_DSS_CHANNEL_LCD:
|
||||
return dsi_get_dsidev_from_id(0);
|
||||
return dss_pll_find("dsi0");
|
||||
case OMAP_DSS_CHANNEL_LCD2:
|
||||
return dsi_get_dsidev_from_id(1);
|
||||
return dss_pll_find("dsi1");
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
@ -85,9 +99,9 @@ static struct platform_device *dpi_get_dsidev(enum omap_channel channel)
|
||||
case OMAPDSS_VER_OMAP5:
|
||||
switch (channel) {
|
||||
case OMAP_DSS_CHANNEL_LCD:
|
||||
return dsi_get_dsidev_from_id(0);
|
||||
return dss_pll_find("dsi0");
|
||||
case OMAP_DSS_CHANNEL_LCD3:
|
||||
return dsi_get_dsidev_from_id(1);
|
||||
return dss_pll_find("dsi1");
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
@ -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 platform_device *dsidev;
|
||||
struct dss_pll *pll;
|
||||
|
||||
/* inputs */
|
||||
|
||||
@ -122,7 +136,7 @@ struct dpi_clk_calc_ctx {
|
||||
|
||||
/* outputs */
|
||||
|
||||
struct dsi_clock_info dsi_cinfo;
|
||||
struct dss_pll_clock_info dsi_cinfo;
|
||||
unsigned long fck;
|
||||
struct dispc_clock_info dispc_cinfo;
|
||||
};
|
||||
@ -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)
|
||||
{
|
||||
struct dpi_clk_calc_ctx *ctx = data;
|
||||
@ -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
|
||||
* 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;
|
||||
|
||||
ctx->dsi_cinfo.regm_dispc = regm_dispc;
|
||||
ctx->dsi_cinfo.dsi_pll_hsdiv_dispc_clk = dispc;
|
||||
ctx->dsi_cinfo.mX[HSDIV_DISPC] = m_dispc;
|
||||
ctx->dsi_cinfo.clkout[HSDIV_DISPC] = dispc;
|
||||
|
||||
return dispc_div_calc(dispc, ctx->pck_min, ctx->pck_max,
|
||||
dpi_calc_dispc_cb, ctx);
|
||||
}
|
||||
|
||||
|
||||
static bool dpi_calc_pll_cb(int regn, int regm, unsigned long fint,
|
||||
unsigned long pll,
|
||||
static bool dpi_calc_pll_cb(int n, int m, unsigned long fint,
|
||||
unsigned long clkdco,
|
||||
void *data)
|
||||
{
|
||||
struct dpi_clk_calc_ctx *ctx = data;
|
||||
|
||||
ctx->dsi_cinfo.regn = regn;
|
||||
ctx->dsi_cinfo.regm = regm;
|
||||
ctx->dsi_cinfo.n = n;
|
||||
ctx->dsi_cinfo.m = m;
|
||||
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,
|
||||
dpi_calc_hsdiv_cb, ctx);
|
||||
return dss_pll_hsdiv_calc(ctx->pll, clkdco,
|
||||
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)
|
||||
@ -200,23 +215,23 @@ static bool dpi_calc_dss_cb(unsigned long fck, void *data)
|
||||
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 pll_min, pll_max;
|
||||
|
||||
clkin = dsi_get_pll_clkin(dpi.dsidev);
|
||||
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
ctx->dsidev = dpi.dsidev;
|
||||
ctx->pll = dpi->pll;
|
||||
ctx->pck_min = pck - 1000;
|
||||
ctx->pck_max = pck + 1000;
|
||||
ctx->dsi_cinfo.clkin = clkin;
|
||||
|
||||
pll_min = 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,
|
||||
dpi_calc_pll_cb, 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,
|
||||
int *pck_div)
|
||||
{
|
||||
@ -260,28 +275,28 @@ static int dpi_set_dsi_clk(enum omap_channel channel,
|
||||
int r;
|
||||
bool ok;
|
||||
|
||||
ok = dpi_dsi_clk_calc(pck_req, &ctx);
|
||||
ok = dpi_dsi_clk_calc(dpi, pck_req, &ctx);
|
||||
if (!ok)
|
||||
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)
|
||||
return r;
|
||||
|
||||
dss_select_lcd_clk_source(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;
|
||||
*pck_div = ctx.dispc_cinfo.pck_div;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dpi_set_dispc_clk(unsigned long pck_req, unsigned long *fck,
|
||||
int *lck_div, int *pck_div)
|
||||
static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req,
|
||||
unsigned long *fck, int *lck_div, int *pck_div)
|
||||
{
|
||||
struct dpi_clk_calc_ctx ctx;
|
||||
int r;
|
||||
@ -295,7 +310,7 @@ static int dpi_set_dispc_clk(unsigned long pck_req, unsigned long *fck,
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dpi.mgr_config.clock_info = ctx.dispc_cinfo;
|
||||
dpi->mgr_config.clock_info = ctx.dispc_cinfo;
|
||||
|
||||
*fck = ctx.fck;
|
||||
*lck_div = ctx.dispc_cinfo.lck_div;
|
||||
@ -304,19 +319,21 @@ static int dpi_set_dispc_clk(unsigned long pck_req, unsigned long *fck,
|
||||
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;
|
||||
unsigned long fck = 0;
|
||||
unsigned long pck;
|
||||
int r = 0;
|
||||
|
||||
if (dpi.dsidev)
|
||||
r = dpi_set_dsi_clk(mgr->id, t->pixelclock, &fck,
|
||||
if (dpi->pll)
|
||||
r = dpi_set_dsi_clk(dpi, mgr->id, t->pixelclock, &fck,
|
||||
&lck_div, &pck_div);
|
||||
else
|
||||
r = dpi_set_dispc_clk(t->pixelclock, &fck,
|
||||
r = dpi_set_dispc_clk(dpi, t->pixelclock, &fck,
|
||||
&lck_div, &pck_div);
|
||||
if (r)
|
||||
return r;
|
||||
@ -335,28 +352,32 @@ static int dpi_set_mode(struct omap_overlay_manager *mgr)
|
||||
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.stallmode = false;
|
||||
dpi.mgr_config.fifohandcheck = false;
|
||||
dpi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
|
||||
|
||||
dpi.mgr_config.video_port_width = dpi.data_lines;
|
||||
dpi->mgr_config.stallmode = false;
|
||||
dpi->mgr_config.fifohandcheck = false;
|
||||
|
||||
dpi.mgr_config.lcden_sig_polarity = 0;
|
||||
dpi->mgr_config.video_port_width = dpi->data_lines;
|
||||
|
||||
dss_mgr_set_lcd_config(mgr, &dpi.mgr_config);
|
||||
dpi->mgr_config.lcden_sig_polarity = 0;
|
||||
|
||||
dss_mgr_set_lcd_config(mgr, &dpi->mgr_config);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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");
|
||||
r = -ENODEV;
|
||||
goto err_no_reg;
|
||||
@ -369,7 +390,7 @@ static int dpi_display_enable(struct omap_dss_device *dssdev)
|
||||
}
|
||||
|
||||
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)
|
||||
goto err_reg_enable;
|
||||
}
|
||||
@ -378,25 +399,21 @@ static int dpi_display_enable(struct omap_dss_device *dssdev)
|
||||
if (r)
|
||||
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)
|
||||
goto err_src_sel;
|
||||
|
||||
if (dpi.dsidev) {
|
||||
r = dsi_runtime_get(dpi.dsidev);
|
||||
if (r)
|
||||
goto err_get_dsi;
|
||||
|
||||
r = dsi_pll_init(dpi.dsidev, 0, 1);
|
||||
if (dpi->pll) {
|
||||
r = dss_pll_enable(dpi->pll);
|
||||
if (r)
|
||||
goto err_dsi_pll_init;
|
||||
}
|
||||
|
||||
r = dpi_set_mode(out->manager);
|
||||
r = dpi_set_mode(dpi);
|
||||
if (r)
|
||||
goto err_set_mode;
|
||||
|
||||
dpi_config_lcd_manager(out->manager);
|
||||
dpi_config_lcd_manager(dpi);
|
||||
|
||||
mdelay(2);
|
||||
|
||||
@ -404,78 +421,80 @@ static int dpi_display_enable(struct omap_dss_device *dssdev)
|
||||
if (r)
|
||||
goto err_mgr_enable;
|
||||
|
||||
mutex_unlock(&dpi.lock);
|
||||
mutex_unlock(&dpi->lock);
|
||||
|
||||
return 0;
|
||||
|
||||
err_mgr_enable:
|
||||
err_set_mode:
|
||||
if (dpi.dsidev)
|
||||
dsi_pll_uninit(dpi.dsidev, true);
|
||||
if (dpi->pll)
|
||||
dss_pll_disable(dpi->pll);
|
||||
err_dsi_pll_init:
|
||||
if (dpi.dsidev)
|
||||
dsi_runtime_put(dpi.dsidev);
|
||||
err_get_dsi:
|
||||
err_src_sel:
|
||||
dispc_runtime_put();
|
||||
err_get_dispc:
|
||||
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_no_out_mgr:
|
||||
err_no_reg:
|
||||
mutex_unlock(&dpi.lock);
|
||||
mutex_unlock(&dpi->lock);
|
||||
return r;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (dpi.dsidev) {
|
||||
if (dpi->pll) {
|
||||
dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
|
||||
dsi_pll_uninit(dpi.dsidev, true);
|
||||
dsi_runtime_put(dpi.dsidev);
|
||||
dss_pll_disable(dpi->pll);
|
||||
}
|
||||
|
||||
dispc_runtime_put();
|
||||
|
||||
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,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
|
||||
|
||||
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,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
mutex_lock(&dpi.lock);
|
||||
struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
|
||||
|
||||
*timings = dpi.timings;
|
||||
mutex_lock(&dpi->lock);
|
||||
|
||||
mutex_unlock(&dpi.lock);
|
||||
*timings = dpi->timings;
|
||||
|
||||
mutex_unlock(&dpi->lock);
|
||||
}
|
||||
|
||||
static int dpi_check_timings(struct omap_dss_device *dssdev,
|
||||
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;
|
||||
unsigned long fck;
|
||||
unsigned long pck;
|
||||
@ -488,12 +507,12 @@ static int dpi_check_timings(struct omap_dss_device *dssdev,
|
||||
if (timings->pixelclock == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (dpi.dsidev) {
|
||||
ok = dpi_dsi_clk_calc(timings->pixelclock, &ctx);
|
||||
if (dpi->pll) {
|
||||
ok = dpi_dsi_clk_calc(dpi, timings->pixelclock, &ctx);
|
||||
if (!ok)
|
||||
return -EINVAL;
|
||||
|
||||
fck = ctx.dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
|
||||
fck = ctx.dsi_cinfo.clkout[HSDIV_DISPC];
|
||||
} else {
|
||||
ok = dpi_dss_clk_calc(timings->pixelclock, &ctx);
|
||||
if (!ok)
|
||||
@ -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)
|
||||
{
|
||||
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;
|
||||
|
||||
/* do initial setup with the PLL to see if it is operational */
|
||||
|
||||
r = dsi_runtime_get(dsidev);
|
||||
r = dss_pll_enable(pll);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = dsi_pll_init(dsidev, 0, 1);
|
||||
if (r) {
|
||||
dsi_runtime_put(dsidev);
|
||||
return r;
|
||||
}
|
||||
|
||||
dsi_pll_uninit(dsidev, true);
|
||||
dsi_runtime_put(dsidev);
|
||||
dss_pll_disable(pll);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dpi_init_regulator(void)
|
||||
static int dpi_init_regulator(struct dpi_data *dpi)
|
||||
{
|
||||
struct regulator *vdds_dsi;
|
||||
|
||||
if (!dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
|
||||
return 0;
|
||||
|
||||
if (dpi.vdds_dsi_reg)
|
||||
if (dpi->vdds_dsi_reg)
|
||||
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 (PTR_ERR(vdds_dsi) != -EPROBE_DEFER)
|
||||
DSSERR("can't get VDDS_DSI regulator\n");
|
||||
return PTR_ERR(vdds_dsi);
|
||||
}
|
||||
|
||||
dpi.vdds_dsi_reg = vdds_dsi;
|
||||
dpi->vdds_dsi_reg = vdds_dsi;
|
||||
|
||||
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;
|
||||
|
||||
dsidev = dpi_get_dsidev(dpi.output.dispc_channel);
|
||||
if (!dsidev)
|
||||
pll = dpi_get_pll(dpi->output.dispc_channel);
|
||||
if (!pll)
|
||||
return;
|
||||
|
||||
if (dpi_verify_dsi_pll(dsidev)) {
|
||||
if (dpi_verify_dsi_pll(pll)) {
|
||||
DSSWARN("DSI PLL not operational\n");
|
||||
return;
|
||||
}
|
||||
|
||||
dpi.dsidev = dsidev;
|
||||
dpi->pll = pll;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -590,7 +604,7 @@ static void dpi_init_pll(void)
|
||||
* the channel in some more dynamic manner, or get the channel as a user
|
||||
* parameter.
|
||||
*/
|
||||
static enum omap_channel dpi_get_channel(void)
|
||||
static enum omap_channel dpi_get_channel(int port_num)
|
||||
{
|
||||
switch (omapdss_get_version()) {
|
||||
case OMAPDSS_VER_OMAP24xx:
|
||||
@ -618,14 +632,15 @@ static enum omap_channel dpi_get_channel(void)
|
||||
static int dpi_connect(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
|
||||
struct omap_overlay_manager *mgr;
|
||||
int r;
|
||||
|
||||
r = dpi_init_regulator();
|
||||
r = dpi_init_regulator(dpi);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dpi_init_pll();
|
||||
dpi_init_pll(dpi);
|
||||
|
||||
mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
|
||||
if (!mgr)
|
||||
@ -676,13 +691,14 @@ static const struct omapdss_dpi_ops dpi_ops = {
|
||||
|
||||
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->id = OMAP_DSS_OUTPUT_DPI;
|
||||
out->output_type = OMAP_DISPLAY_TYPE_DPI;
|
||||
out->name = "dpi.0";
|
||||
out->dispc_channel = dpi_get_channel();
|
||||
out->dispc_channel = dpi_get_channel(0);
|
||||
out->ops.dpi = &dpi_ops;
|
||||
out->owner = THIS_MODULE;
|
||||
|
||||
@ -691,16 +707,69 @@ static void dpi_init_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);
|
||||
}
|
||||
|
||||
static int omap_dpi_probe(struct platform_device *pdev)
|
||||
{
|
||||
dpi.pdev = pdev;
|
||||
struct dpi_data *dpi;
|
||||
|
||||
mutex_init(&dpi.lock);
|
||||
dpi = devm_kzalloc(&pdev->dev, sizeof(*dpi), GFP_KERNEL);
|
||||
if (!dpi)
|
||||
return -ENOMEM;
|
||||
|
||||
dpi->pdev = pdev;
|
||||
|
||||
dev_set_drvdata(&pdev->dev, dpi);
|
||||
|
||||
mutex_init(&dpi->lock);
|
||||
|
||||
dpi_init_output(pdev);
|
||||
|
||||
@ -736,10 +805,15 @@ void __exit dpi_uninit_platform_driver(void)
|
||||
|
||||
int __init dpi_init_port(struct platform_device *pdev, struct device_node *port)
|
||||
{
|
||||
struct dpi_data *dpi;
|
||||
struct device_node *ep;
|
||||
u32 datalines;
|
||||
int r;
|
||||
|
||||
dpi = devm_kzalloc(&pdev->dev, sizeof(*dpi), GFP_KERNEL);
|
||||
if (!dpi)
|
||||
return -ENOMEM;
|
||||
|
||||
ep = omapdss_of_get_next_endpoint(port, NULL);
|
||||
if (!ep)
|
||||
return 0;
|
||||
@ -750,17 +824,18 @@ int __init dpi_init_port(struct platform_device *pdev, struct device_node *port)
|
||||
goto err_datalines;
|
||||
}
|
||||
|
||||
dpi.data_lines = datalines;
|
||||
dpi->data_lines = datalines;
|
||||
|
||||
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;
|
||||
|
||||
@ -770,10 +845,12 @@ int __init dpi_init_port(struct platform_device *pdev, struct device_node *port)
|
||||
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;
|
||||
|
||||
dpi_uninit_output(dpi.pdev);
|
||||
dpi_uninit_output_port(port);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -20,6 +20,8 @@
|
||||
|
||||
#include <video/omapdss.h>
|
||||
|
||||
#include "dss.h"
|
||||
|
||||
struct device_node *
|
||||
omapdss_of_get_next_port(const struct device_node *parent,
|
||||
struct device_node *prev)
|
||||
@ -84,20 +86,17 @@ omapdss_of_get_next_endpoint(const struct device_node *parent,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omapdss_of_get_next_endpoint);
|
||||
|
||||
static struct device_node *
|
||||
omapdss_of_get_remote_device_node(const struct device_node *node)
|
||||
struct device_node *dss_of_port_get_parent_device(struct device_node *port)
|
||||
{
|
||||
struct device_node *np;
|
||||
int i;
|
||||
|
||||
np = of_parse_phandle(node, "remote-endpoint", 0);
|
||||
|
||||
if (!np)
|
||||
if (!port)
|
||||
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;
|
||||
|
||||
prop = of_find_property(np, "compatible", NULL);
|
||||
@ -111,6 +110,31 @@ omapdss_of_get_remote_device_node(const struct device_node *node)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
u32 dss_of_port_get_port_number(struct device_node *port)
|
||||
{
|
||||
int r;
|
||||
u32 reg;
|
||||
|
||||
r = of_property_read_u32(port, "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 *
|
||||
omapdss_of_get_first_endpoint(const struct device_node *parent)
|
||||
{
|
||||
@ -133,27 +157,25 @@ struct omap_dss_device *
|
||||
omapdss_of_find_source_for_first_ep(struct device_node *node)
|
||||
{
|
||||
struct device_node *ep;
|
||||
struct device_node *src_node;
|
||||
struct device_node *src_port;
|
||||
struct omap_dss_device *src;
|
||||
|
||||
ep = omapdss_of_get_first_endpoint(node);
|
||||
if (!ep)
|
||||
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);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
of_node_put(ep);
|
||||
|
||||
if (!src_node)
|
||||
return ERR_PTR(-EINVAL);
|
||||
src = omap_dss_find_output_by_port_node(src_port);
|
||||
|
||||
src = omap_dss_find_output_by_node(src_node);
|
||||
of_node_put(src_port);
|
||||
|
||||
of_node_put(src_node);
|
||||
|
||||
if (!src)
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
|
||||
return src;
|
||||
return src ? src : ERR_PTR(-EPROBE_DEFER);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omapdss_of_find_source_for_first_ep);
|
||||
|
@ -70,7 +70,9 @@ struct dss_features {
|
||||
u8 fck_div_max;
|
||||
u8 dss_fck_multiplier;
|
||||
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 {
|
||||
@ -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)
|
||||
{
|
||||
struct platform_device *dsidev;
|
||||
int b;
|
||||
u8 start, end;
|
||||
|
||||
@ -304,13 +305,9 @@ static void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src)
|
||||
break;
|
||||
case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
|
||||
b = 1;
|
||||
dsidev = dsi_get_dsidev_from_id(0);
|
||||
dsi_wait_pll_hsdiv_dispc_active(dsidev);
|
||||
break;
|
||||
case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
|
||||
b = 2;
|
||||
dsidev = dsi_get_dsidev_from_id(1);
|
||||
dsi_wait_pll_hsdiv_dispc_active(dsidev);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
@ -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,
|
||||
enum omap_dss_clk_source clk_src)
|
||||
{
|
||||
struct platform_device *dsidev;
|
||||
int b, pos;
|
||||
|
||||
switch (clk_src) {
|
||||
@ -337,14 +333,10 @@ void dss_select_dsi_clk_source(int dsi_module,
|
||||
case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI:
|
||||
BUG_ON(dsi_module != 0);
|
||||
b = 1;
|
||||
dsidev = dsi_get_dsidev_from_id(0);
|
||||
dsi_wait_pll_hsdiv_dsi_active(dsidev);
|
||||
break;
|
||||
case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI:
|
||||
BUG_ON(dsi_module != 1);
|
||||
b = 1;
|
||||
dsidev = dsi_get_dsidev_from_id(1);
|
||||
dsi_wait_pll_hsdiv_dsi_active(dsidev);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
@ -360,7 +352,6 @@ void dss_select_dsi_clk_source(int dsi_module,
|
||||
void dss_select_lcd_clk_source(enum omap_channel channel,
|
||||
enum omap_dss_clk_source clk_src)
|
||||
{
|
||||
struct platform_device *dsidev;
|
||||
int b, ix, pos;
|
||||
|
||||
if (!dss_has_feature(FEAT_LCD_CLK_SRC)) {
|
||||
@ -375,15 +366,11 @@ void dss_select_lcd_clk_source(enum omap_channel channel,
|
||||
case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
|
||||
BUG_ON(channel != OMAP_DSS_CHANNEL_LCD);
|
||||
b = 1;
|
||||
dsidev = dsi_get_dsidev_from_id(0);
|
||||
dsi_wait_pll_hsdiv_dispc_active(dsidev);
|
||||
break;
|
||||
case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
|
||||
BUG_ON(channel != OMAP_DSS_CHANNEL_LCD2 &&
|
||||
channel != OMAP_DSS_CHANNEL_LCD3);
|
||||
b = 1;
|
||||
dsidev = dsi_get_dsidev_from_id(1);
|
||||
dsi_wait_pll_hsdiv_dispc_active(dsidev);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
@ -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);
|
||||
}
|
||||
|
||||
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)
|
||||
return -EINVAL;
|
||||
@ -572,7 +559,7 @@ static int dss_dpi_select_source_omap2_omap3(enum omap_channel channel)
|
||||
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;
|
||||
|
||||
@ -592,7 +579,7 @@ static int dss_dpi_select_source_omap4(enum omap_channel channel)
|
||||
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;
|
||||
|
||||
@ -618,9 +605,9 @@ static int dss_dpi_select_source_omap5(enum omap_channel channel)
|
||||
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)
|
||||
@ -689,6 +676,16 @@ void dss_debug_dump_clocks(struct seq_file *s)
|
||||
}
|
||||
#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 = {
|
||||
/*
|
||||
* 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 = {
|
||||
.dss_fck_multiplier = 2,
|
||||
.parent_clk_name = "core_ck",
|
||||
.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 = {
|
||||
@ -705,6 +704,8 @@ static const struct dss_features omap34xx_dss_feats __initconst = {
|
||||
.dss_fck_multiplier = 2,
|
||||
.parent_clk_name = "dpll4_ck",
|
||||
.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 = {
|
||||
@ -712,6 +713,8 @@ static const struct dss_features omap3630_dss_feats __initconst = {
|
||||
.dss_fck_multiplier = 1,
|
||||
.parent_clk_name = "dpll4_ck",
|
||||
.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 = {
|
||||
@ -719,6 +722,8 @@ static const struct dss_features omap44xx_dss_feats __initconst = {
|
||||
.dss_fck_multiplier = 1,
|
||||
.parent_clk_name = "dpll_per_x2_ck",
|
||||
.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 = {
|
||||
@ -726,6 +731,8 @@ static const struct dss_features omap54xx_dss_feats __initconst = {
|
||||
.dss_fck_multiplier = 1,
|
||||
.parent_clk_name = "dpll_per_x2_ck",
|
||||
.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 = {
|
||||
@ -733,6 +740,8 @@ static const struct dss_features am43xx_dss_feats __initconst = {
|
||||
.dss_fck_multiplier = 0,
|
||||
.parent_clk_name = NULL,
|
||||
.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)
|
||||
@ -798,37 +807,77 @@ static int __init dss_init_ports(struct platform_device *pdev)
|
||||
if (!port)
|
||||
return 0;
|
||||
|
||||
if (dss.feat->num_ports == 0)
|
||||
return 0;
|
||||
|
||||
do {
|
||||
enum omap_display_type port_type;
|
||||
u32 reg;
|
||||
|
||||
r = of_property_read_u32(port, "reg", ®);
|
||||
if (r)
|
||||
reg = 0;
|
||||
|
||||
#ifdef CONFIG_OMAP2_DSS_DPI
|
||||
if (reg == 0)
|
||||
if (reg >= dss.feat->num_ports)
|
||||
continue;
|
||||
|
||||
port_type = dss.feat->ports[reg];
|
||||
|
||||
switch (port_type) {
|
||||
case OMAP_DISPLAY_TYPE_DPI:
|
||||
dpi_init_port(pdev, port);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OMAP2_DSS_SDI
|
||||
if (reg == 1)
|
||||
break;
|
||||
case OMAP_DISPLAY_TYPE_SDI:
|
||||
sdi_init_port(pdev, port);
|
||||
#endif
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} while ((port = omapdss_of_get_next_port(parent, port)) != NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit dss_uninit_ports(void)
|
||||
static void __exit dss_uninit_ports(struct platform_device *pdev)
|
||||
{
|
||||
#ifdef CONFIG_OMAP2_DSS_DPI
|
||||
dpi_uninit_port();
|
||||
#endif
|
||||
struct device_node *parent = pdev->dev.of_node;
|
||||
struct device_node *port;
|
||||
|
||||
#ifdef CONFIG_OMAP2_DSS_SDI
|
||||
sdi_uninit_port();
|
||||
#endif
|
||||
if (parent == NULL)
|
||||
return;
|
||||
|
||||
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", ®);
|
||||
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 */
|
||||
@ -910,7 +959,7 @@ static int __init omap_dsshw_probe(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);
|
||||
|
||||
|
@ -100,6 +100,69 @@ enum dss_writeback_channel {
|
||||
DSS_WB_LCD3_MGR = 7,
|
||||
};
|
||||
|
||||
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 */
|
||||
unsigned long fint;
|
||||
unsigned long clkdco;
|
||||
unsigned long clkout[DSS_PLL_MAX_HSDIVS];
|
||||
|
||||
/* dividers */
|
||||
u16 n;
|
||||
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 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 */
|
||||
unsigned long lck;
|
||||
@ -110,27 +173,6 @@ struct dispc_clock_info {
|
||||
u16 pck_div;
|
||||
};
|
||||
|
||||
struct dsi_clock_info {
|
||||
/* rates that we get with dividers below */
|
||||
unsigned long fint;
|
||||
unsigned long clkin4ddr;
|
||||
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 */
|
||||
u16 regn;
|
||||
u16 regm;
|
||||
u16 regm_dispc; /* OMAP3: REGM3
|
||||
* OMAP4: REGM4 */
|
||||
u16 regm_dsi; /* OMAP3: REGM4
|
||||
* OMAP4: REGM5 */
|
||||
u16 lp_clk_div;
|
||||
};
|
||||
|
||||
struct dss_lcd_mgr_config {
|
||||
enum dss_io_pad_mode io_pad_mode;
|
||||
|
||||
@ -209,12 +251,16 @@ int dss_init_platform_driver(void) __init;
|
||||
void dss_uninit_platform_driver(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);
|
||||
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);
|
||||
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)
|
||||
void dss_debug_dump_clocks(struct seq_file *s);
|
||||
#endif
|
||||
@ -244,16 +290,22 @@ bool dss_div_calc(unsigned long pck, unsigned long fck_min,
|
||||
int sdi_init_platform_driver(void) __init;
|
||||
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;
|
||||
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 */
|
||||
|
||||
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
|
||||
|
||||
struct dentry;
|
||||
@ -262,104 +314,36 @@ struct file_operations;
|
||||
int dsi_init_platform_driver(void) __init;
|
||||
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_irq_handler(void);
|
||||
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
|
||||
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)
|
||||
{
|
||||
WARN("%s: DSI not compiled in, returning pixel_size as 0\n", __func__);
|
||||
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
|
||||
|
||||
/* DPI */
|
||||
int dpi_init_platform_driver(void) __init;
|
||||
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;
|
||||
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 */
|
||||
int dispc_init_platform_driver(void) __init;
|
||||
@ -438,4 +422,29 @@ static inline void dss_collect_irq_stats(u32 irqstatus, unsigned *irq_arr)
|
||||
}
|
||||
#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
|
||||
|
@ -72,10 +72,6 @@ static const struct dss_reg_field omap2_dss_reg_fields[] = {
|
||||
[FEAT_REG_HORIZONTALACCU] = { 9, 0 },
|
||||
[FEAT_REG_VERTICALACCU] = { 25, 16 },
|
||||
[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[] = {
|
||||
@ -87,10 +83,6 @@ static const struct dss_reg_field omap3_dss_reg_fields[] = {
|
||||
[FEAT_REG_HORIZONTALACCU] = { 9, 0 },
|
||||
[FEAT_REG_VERTICALACCU] = { 25, 16 },
|
||||
[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[] = {
|
||||
@ -113,10 +105,6 @@ static const struct dss_reg_field omap4_dss_reg_fields[] = {
|
||||
[FEAT_REG_HORIZONTALACCU] = { 10, 0 },
|
||||
[FEAT_REG_VERTICALACCU] = { 26, 16 },
|
||||
[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[] = {
|
||||
@ -128,10 +116,6 @@ static const struct dss_reg_field omap5_dss_reg_fields[] = {
|
||||
[FEAT_REG_HORIZONTALACCU] = { 10, 0 },
|
||||
[FEAT_REG_VERTICALACCU] = { 26, 16 },
|
||||
[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[] = {
|
||||
@ -437,12 +421,6 @@ static const char * const omap5_dss_clk_source_names[] = {
|
||||
static const struct dss_param_range omap2_dss_param_range[] = {
|
||||
[FEAT_PARAM_DSS_FCK] = { 0, 133000000 },
|
||||
[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 },
|
||||
/*
|
||||
* 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[] = {
|
||||
static const struct dss_param_range omap3_dss_param_range[] = {
|
||||
[FEAT_PARAM_DSS_FCK] = { 0, 173000000 },
|
||||
[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_DSI_FCK] = { 0, 173000000 },
|
||||
[FEAT_PARAM_DOWNSCALE] = { 1, 4 },
|
||||
@ -475,11 +448,6 @@ static const struct dss_param_range am43xx_dss_param_range[] = {
|
||||
static const struct dss_param_range omap4_dss_param_range[] = {
|
||||
[FEAT_PARAM_DSS_FCK] = { 0, 186000000 },
|
||||
[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_DSI_FCK] = { 0, 170000000 },
|
||||
[FEAT_PARAM_DOWNSCALE] = { 1, 4 },
|
||||
@ -489,11 +457,6 @@ static const struct dss_param_range omap4_dss_param_range[] = {
|
||||
static const struct dss_param_range omap5_dss_param_range[] = {
|
||||
[FEAT_PARAM_DSS_FCK] = { 0, 209250000 },
|
||||
[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_DSI_FCK] = { 0, 209250000 },
|
||||
[FEAT_PARAM_DOWNSCALE] = { 1, 4 },
|
||||
@ -517,7 +480,6 @@ static const enum dss_feat_id omap3430_dss_feat_list[] = {
|
||||
FEAT_LINEBUFFERSPLIT,
|
||||
FEAT_ROWREPEATENABLE,
|
||||
FEAT_RESIZECONF,
|
||||
FEAT_DSI_PLL_FREQSEL,
|
||||
FEAT_DSI_REVERSE_TXCLKESC,
|
||||
FEAT_VENC_REQUIRES_TV_DAC_CLK,
|
||||
FEAT_CPR,
|
||||
@ -537,7 +499,6 @@ static const enum dss_feat_id am35xx_dss_feat_list[] = {
|
||||
FEAT_LINEBUFFERSPLIT,
|
||||
FEAT_ROWREPEATENABLE,
|
||||
FEAT_RESIZECONF,
|
||||
FEAT_DSI_PLL_FREQSEL,
|
||||
FEAT_DSI_REVERSE_TXCLKESC,
|
||||
FEAT_VENC_REQUIRES_TV_DAC_CLK,
|
||||
FEAT_CPR,
|
||||
@ -572,7 +533,6 @@ static const enum dss_feat_id omap3630_dss_feat_list[] = {
|
||||
FEAT_ROWREPEATENABLE,
|
||||
FEAT_RESIZECONF,
|
||||
FEAT_DSI_PLL_PWR_BUG,
|
||||
FEAT_DSI_PLL_FREQSEL,
|
||||
FEAT_CPR,
|
||||
FEAT_PRELOAD,
|
||||
FEAT_FIR_COEF_V,
|
||||
@ -654,8 +614,6 @@ static const enum dss_feat_id omap5_dss_feat_list[] = {
|
||||
FEAT_ALPHA_FREE_ZORDER,
|
||||
FEAT_FIFO_MERGE,
|
||||
FEAT_BURST_2D,
|
||||
FEAT_DSI_PLL_SELFREQDCO,
|
||||
FEAT_DSI_PLL_REFSEL,
|
||||
FEAT_DSI_PHY_DCC,
|
||||
FEAT_MFLAG,
|
||||
};
|
||||
|
@ -41,7 +41,6 @@ enum dss_feat_id {
|
||||
FEAT_LCD_CLK_SRC,
|
||||
/* DSI-PLL power command 0x3 is not working */
|
||||
FEAT_DSI_PLL_PWR_BUG,
|
||||
FEAT_DSI_PLL_FREQSEL,
|
||||
FEAT_DSI_DCS_CMD_CONFIG_VC,
|
||||
FEAT_DSI_VC_OCP_WIDTH,
|
||||
FEAT_DSI_REVERSE_TXCLKESC,
|
||||
@ -61,8 +60,6 @@ enum dss_feat_id {
|
||||
/* An unknown HW bug causing the normal FIFO thresholds not to work */
|
||||
FEAT_OMAP3_DSI_FIFO_BUG,
|
||||
FEAT_BURST_2D,
|
||||
FEAT_DSI_PLL_SELFREQDCO,
|
||||
FEAT_DSI_PLL_REFSEL,
|
||||
FEAT_DSI_PHY_DCC,
|
||||
FEAT_MFLAG,
|
||||
};
|
||||
@ -77,20 +74,11 @@ enum dss_feat_reg_field {
|
||||
FEAT_REG_HORIZONTALACCU,
|
||||
FEAT_REG_VERTICALACCU,
|
||||
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 {
|
||||
FEAT_PARAM_DSS_FCK,
|
||||
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_DSI_FCK,
|
||||
FEAT_PARAM_DOWNSCALE,
|
||||
|
@ -101,13 +101,6 @@ enum hdmi_core_hdmi_dvi {
|
||||
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 {
|
||||
HDMI_PACK_10b_RGB_YUV444 = 0,
|
||||
HDMI_PACK_24b_RGB_YUV444_YUV422 = 1,
|
||||
@ -160,7 +153,8 @@ enum hdmi_audio_blk_strt_end_sig {
|
||||
|
||||
enum hdmi_core_audio_layout {
|
||||
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 {
|
||||
@ -191,17 +185,6 @@ struct hdmi_config {
|
||||
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 {
|
||||
enum hdmi_stereo_channels stereo_channels;
|
||||
u8 active_chnnls_msk;
|
||||
@ -249,12 +232,15 @@ struct hdmi_core_audio_config {
|
||||
|
||||
struct hdmi_wp_data {
|
||||
void __iomem *base;
|
||||
phys_addr_t phys_base;
|
||||
};
|
||||
|
||||
struct hdmi_pll_data {
|
||||
struct dss_pll pll;
|
||||
|
||||
void __iomem *base;
|
||||
|
||||
struct hdmi_pll_info info;
|
||||
struct hdmi_wp_data *wp;
|
||||
};
|
||||
|
||||
struct hdmi_phy_data {
|
||||
@ -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,
|
||||
struct omap_video_timings *timings, struct hdmi_config *param);
|
||||
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 */
|
||||
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_compute(struct hdmi_pll_data *pll, unsigned long clkin, int phy);
|
||||
int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll);
|
||||
void hdmi_pll_compute(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 */
|
||||
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);
|
||||
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);
|
||||
@ -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,
|
||||
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_wp_audio_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,
|
||||
struct hdmi_audio_format *aud_fmt);
|
||||
void hdmi_wp_audio_config_dma(struct hdmi_wp_data *wp,
|
||||
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
|
||||
|
@ -33,29 +33,14 @@
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <video/omapdss.h>
|
||||
#include <sound/omap-hdmi-audio.h>
|
||||
|
||||
#include "hdmi4_core.h"
|
||||
#include "dss.h"
|
||||
#include "dss_features.h"
|
||||
#include "hdmi.h"
|
||||
|
||||
static struct {
|
||||
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 struct omap_hdmi hdmi;
|
||||
|
||||
static int hdmi_runtime_get(void)
|
||||
{
|
||||
@ -117,7 +102,7 @@ static int hdmi_init_regulator(void)
|
||||
int r;
|
||||
struct regulator *reg;
|
||||
|
||||
if (hdmi.vdda_hdmi_dac_reg != NULL)
|
||||
if (hdmi.vdda_reg != NULL)
|
||||
return 0;
|
||||
|
||||
reg = devm_regulator_get(&hdmi.pdev->dev, "vdda");
|
||||
@ -137,7 +122,7 @@ static int hdmi_init_regulator(void)
|
||||
}
|
||||
}
|
||||
|
||||
hdmi.vdda_hdmi_dac_reg = reg;
|
||||
hdmi.vdda_reg = reg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -146,7 +131,7 @@ static int hdmi_power_on_core(struct omap_dss_device *dssdev)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = regulator_enable(hdmi.vdda_hdmi_dac_reg);
|
||||
r = regulator_enable(hdmi.vdda_reg);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
@ -162,7 +147,7 @@ static int hdmi_power_on_core(struct omap_dss_device *dssdev)
|
||||
return 0;
|
||||
|
||||
err_runtime_get:
|
||||
regulator_disable(hdmi.vdda_hdmi_dac_reg);
|
||||
regulator_disable(hdmi.vdda_reg);
|
||||
|
||||
return r;
|
||||
}
|
||||
@ -172,7 +157,7 @@ static void hdmi_power_off_core(struct omap_dss_device *dssdev)
|
||||
hdmi.core_enabled = false;
|
||||
|
||||
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)
|
||||
@ -180,8 +165,8 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
|
||||
int r;
|
||||
struct omap_video_timings *p;
|
||||
struct omap_overlay_manager *mgr = hdmi.output.manager;
|
||||
unsigned long phy;
|
||||
struct hdmi_wp_data *wp = &hdmi.wp;
|
||||
struct dss_pll_clock_info hdmi_cinfo = { 0 };
|
||||
|
||||
r = hdmi_power_on_core(dssdev);
|
||||
if (r)
|
||||
@ -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);
|
||||
|
||||
/* the functions below use kHz pixel clock. TODO: change to Hz */
|
||||
phy = p->pixelclock / 1000;
|
||||
hdmi_pll_compute(&hdmi.pll, p->pixelclock, &hdmi_cinfo);
|
||||
|
||||
hdmi_pll_compute(&hdmi.pll, clk_get_rate(hdmi.sys_clk), phy);
|
||||
|
||||
/* config the PLL and PHY hdmi_set_pll_pwrfirst */
|
||||
r = hdmi_pll_enable(&hdmi.pll, &hdmi.wp);
|
||||
r = dss_pll_enable(&hdmi.pll.pll);
|
||||
if (r) {
|
||||
DSSDBG("Failed to lock PLL\n");
|
||||
DSSERR("Failed to enable PLL\n");
|
||||
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) {
|
||||
DSSDBG("Failed to configure PHY\n");
|
||||
goto err_phy_cfg;
|
||||
@ -244,7 +232,8 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
|
||||
err_phy_cfg:
|
||||
hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
|
||||
err_phy_pwr:
|
||||
hdmi_pll_disable(&hdmi.pll, &hdmi.wp);
|
||||
err_pll_cfg:
|
||||
dss_pll_disable(&hdmi.pll.pll);
|
||||
err_pll_enable:
|
||||
hdmi_power_off_core(dssdev);
|
||||
return -EIO;
|
||||
@ -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_pll_disable(&hdmi.pll, &hdmi.wp);
|
||||
dss_pll_disable(&hdmi.pll.pll);
|
||||
|
||||
hdmi_power_off_core(dssdev);
|
||||
}
|
||||
@ -352,6 +341,8 @@ static int hdmi_display_enable(struct omap_dss_device *dssdev)
|
||||
goto err0;
|
||||
}
|
||||
|
||||
hdmi.display_enabled = true;
|
||||
|
||||
mutex_unlock(&hdmi.lock);
|
||||
return 0;
|
||||
|
||||
@ -366,8 +357,13 @@ static void hdmi_display_disable(struct omap_dss_device *dssdev)
|
||||
|
||||
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.display_enabled = false;
|
||||
|
||||
mutex_unlock(&hdmi.lock);
|
||||
}
|
||||
|
||||
@ -404,21 +400,6 @@ static void hdmi_core_disable(struct omap_dss_device *dssdev)
|
||||
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,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
@ -484,112 +465,6 @@ static int hdmi_read_edid(struct omap_dss_device *dssdev,
|
||||
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,
|
||||
const struct hdmi_avi_infoframe *avi)
|
||||
{
|
||||
@ -618,13 +493,6 @@ static const struct omapdss_hdmi_ops hdmi_ops = {
|
||||
.read_edid = hdmi_read_edid,
|
||||
.set_infoframe = hdmi_set_infoframe,
|
||||
.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)
|
||||
@ -642,7 +510,7 @@ static void hdmi_init_output(struct platform_device *pdev)
|
||||
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;
|
||||
|
||||
@ -671,6 +539,112 @@ static int hdmi_probe_of(struct platform_device *pdev)
|
||||
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 */
|
||||
static int omapdss_hdmihw_probe(struct platform_device *pdev)
|
||||
{
|
||||
@ -678,6 +652,7 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
|
||||
int irq;
|
||||
|
||||
hdmi.pdev = pdev;
|
||||
dev_set_drvdata(&pdev->dev, &hdmi);
|
||||
|
||||
mutex_init(&hdmi.lock);
|
||||
|
||||
@ -691,28 +666,23 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = hdmi_pll_init(pdev, &hdmi.pll);
|
||||
r = hdmi_pll_init(pdev, &hdmi.pll, &hdmi.wp);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = hdmi_phy_init(pdev, &hdmi.phy);
|
||||
if (r)
|
||||
return r;
|
||||
goto err;
|
||||
|
||||
r = hdmi4_core_init(pdev, &hdmi.core);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = hdmi_get_clocks(pdev);
|
||||
if (r) {
|
||||
DSSERR("can't get clocks\n");
|
||||
return r;
|
||||
}
|
||||
goto err;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
DSSERR("platform_get_irq failed\n");
|
||||
return -ENODEV;
|
||||
r = -ENODEV;
|
||||
goto err;
|
||||
}
|
||||
|
||||
r = devm_request_threaded_irq(&pdev->dev, irq,
|
||||
@ -720,22 +690,38 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
|
||||
IRQF_ONESHOT, "OMAP HDMI", &hdmi.wp);
|
||||
if (r) {
|
||||
DSSERR("HDMI IRQ request failed\n");
|
||||
return r;
|
||||
goto err;
|
||||
}
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
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);
|
||||
|
||||
return 0;
|
||||
err:
|
||||
hdmi_pll_uninit(&hdmi.pll);
|
||||
return r;
|
||||
}
|
||||
|
||||
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_pll_uninit(&hdmi.pll);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
@ -743,8 +729,6 @@ static int __exit omapdss_hdmihw_remove(struct platform_device *pdev)
|
||||
|
||||
static int hdmi_runtime_suspend(struct device *dev)
|
||||
{
|
||||
clk_disable_unprepare(hdmi.sys_clk);
|
||||
|
||||
dispc_runtime_put();
|
||||
|
||||
return 0;
|
||||
@ -758,8 +742,6 @@ static int hdmi_runtime_resume(struct device *dev)
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
clk_prepare_enable(hdmi.sys_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -31,10 +31,8 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/seq_file.h>
|
||||
#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
|
||||
#include <sound/asound.h>
|
||||
#include <sound/asoundef.h>
|
||||
#endif
|
||||
|
||||
#include "hdmi4_core.h"
|
||||
#include "dss_features.h"
|
||||
@ -530,7 +528,6 @@ void hdmi4_core_dump(struct hdmi_core_data *core, struct seq_file *s)
|
||||
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,
|
||||
struct hdmi_core_audio_config *cfg)
|
||||
{
|
||||
@ -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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct resource *res;
|
||||
|
@ -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);
|
||||
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);
|
||||
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,
|
||||
struct omap_dss_audio *audio, u32 pclk);
|
||||
int hdmi4_audio_get_dma_port(u32 *offset, u32 *size);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -38,29 +38,13 @@
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <video/omapdss.h>
|
||||
#include <sound/omap-hdmi-audio.h>
|
||||
|
||||
#include "hdmi5_core.h"
|
||||
#include "dss.h"
|
||||
#include "dss_features.h"
|
||||
|
||||
static struct {
|
||||
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 struct omap_hdmi hdmi;
|
||||
|
||||
static int hdmi_runtime_get(void)
|
||||
{
|
||||
@ -198,7 +182,7 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
|
||||
int r;
|
||||
struct omap_video_timings *p;
|
||||
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);
|
||||
if (r)
|
||||
@ -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);
|
||||
|
||||
/* the functions below use kHz pixel clock. TODO: change to Hz */
|
||||
phy = p->pixelclock / 1000;
|
||||
|
||||
hdmi_pll_compute(&hdmi.pll, clk_get_rate(hdmi.sys_clk), phy);
|
||||
hdmi_pll_compute(&hdmi.pll, p->pixelclock, &hdmi_cinfo);
|
||||
|
||||
/* disable and clear irqs */
|
||||
hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff);
|
||||
hdmi_wp_set_irqstatus(&hdmi.wp,
|
||||
hdmi_wp_get_irqstatus(&hdmi.wp));
|
||||
|
||||
/* config the PLL and PHY hdmi_set_pll_pwrfirst */
|
||||
r = hdmi_pll_enable(&hdmi.pll, &hdmi.wp);
|
||||
r = dss_pll_enable(&hdmi.pll.pll);
|
||||
if (r) {
|
||||
DSSDBG("Failed to lock PLL\n");
|
||||
DSSERR("Failed to enable PLL\n");
|
||||
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) {
|
||||
DSSDBG("Failed to start PHY\n");
|
||||
goto err_phy_cfg;
|
||||
@ -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);
|
||||
err_phy_pwr:
|
||||
err_phy_cfg:
|
||||
hdmi_pll_disable(&hdmi.pll, &hdmi.wp);
|
||||
err_pll_cfg:
|
||||
dss_pll_disable(&hdmi.pll.pll);
|
||||
err_pll_enable:
|
||||
hdmi_power_off_core(dssdev);
|
||||
return -EIO;
|
||||
@ -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_pll_disable(&hdmi.pll, &hdmi.wp);
|
||||
dss_pll_disable(&hdmi.pll.pll);
|
||||
|
||||
hdmi_power_off_core(dssdev);
|
||||
}
|
||||
@ -290,6 +278,10 @@ static int hdmi_display_check_timing(struct omap_dss_device *dssdev,
|
||||
{
|
||||
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))
|
||||
return -EINVAL;
|
||||
|
||||
@ -377,6 +369,8 @@ static int hdmi_display_enable(struct omap_dss_device *dssdev)
|
||||
goto err0;
|
||||
}
|
||||
|
||||
hdmi.display_enabled = true;
|
||||
|
||||
mutex_unlock(&hdmi.lock);
|
||||
return 0;
|
||||
|
||||
@ -391,8 +385,13 @@ static void hdmi_display_disable(struct omap_dss_device *dssdev)
|
||||
|
||||
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.display_enabled = false;
|
||||
|
||||
mutex_unlock(&hdmi.lock);
|
||||
}
|
||||
|
||||
@ -429,21 +428,6 @@ static void hdmi_core_disable(struct omap_dss_device *dssdev)
|
||||
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,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
@ -509,112 +493,6 @@ static int hdmi_read_edid(struct omap_dss_device *dssdev,
|
||||
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,
|
||||
const struct hdmi_avi_infoframe *avi)
|
||||
{
|
||||
@ -643,13 +521,6 @@ static const struct omapdss_hdmi_ops hdmi_ops = {
|
||||
.read_edid = hdmi_read_edid,
|
||||
.set_infoframe = hdmi_set_infoframe,
|
||||
.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)
|
||||
@ -667,7 +538,7 @@ static void hdmi_init_output(struct platform_device *pdev)
|
||||
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;
|
||||
|
||||
@ -696,6 +567,119 @@ static int hdmi_probe_of(struct platform_device *pdev)
|
||||
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 */
|
||||
static int omapdss_hdmihw_probe(struct platform_device *pdev)
|
||||
{
|
||||
@ -703,6 +687,7 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
|
||||
int irq;
|
||||
|
||||
hdmi.pdev = pdev;
|
||||
dev_set_drvdata(&pdev->dev, &hdmi);
|
||||
|
||||
mutex_init(&hdmi.lock);
|
||||
|
||||
@ -716,28 +701,23 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = hdmi_pll_init(pdev, &hdmi.pll);
|
||||
r = hdmi_pll_init(pdev, &hdmi.pll, &hdmi.wp);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = hdmi_phy_init(pdev, &hdmi.phy);
|
||||
if (r)
|
||||
return r;
|
||||
goto err;
|
||||
|
||||
r = hdmi5_core_init(pdev, &hdmi.core);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = hdmi_get_clocks(pdev);
|
||||
if (r) {
|
||||
DSSERR("can't get clocks\n");
|
||||
return r;
|
||||
}
|
||||
goto err;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
DSSERR("platform_get_irq failed\n");
|
||||
return -ENODEV;
|
||||
r = -ENODEV;
|
||||
goto err;
|
||||
}
|
||||
|
||||
r = devm_request_threaded_irq(&pdev->dev, irq,
|
||||
@ -745,22 +725,38 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
|
||||
IRQF_ONESHOT, "OMAP HDMI", &hdmi.wp);
|
||||
if (r) {
|
||||
DSSERR("HDMI IRQ request failed\n");
|
||||
return r;
|
||||
goto err;
|
||||
}
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
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);
|
||||
|
||||
return 0;
|
||||
err:
|
||||
hdmi_pll_uninit(&hdmi.pll);
|
||||
return r;
|
||||
}
|
||||
|
||||
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_pll_uninit(&hdmi.pll);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
@ -768,8 +764,6 @@ static int __exit omapdss_hdmihw_remove(struct platform_device *pdev)
|
||||
|
||||
static int hdmi_runtime_suspend(struct device *dev)
|
||||
{
|
||||
clk_disable_unprepare(hdmi.sys_clk);
|
||||
|
||||
dispc_runtime_put();
|
||||
|
||||
return 0;
|
||||
@ -783,8 +777,6 @@ static int hdmi_runtime_resume(struct device *dev)
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
clk_prepare_enable(hdmi.sys_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -30,10 +30,8 @@
|
||||
#include <linux/string.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#if defined(CONFIG_OMAP5_DSS_HDMI_AUDIO)
|
||||
#include <sound/asound.h>
|
||||
#include <sound/asoundef.h>
|
||||
#endif
|
||||
|
||||
#include "hdmi5_core.h"
|
||||
|
||||
@ -644,9 +642,6 @@ void hdmi5_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
|
||||
hdmi_core_enable_interrupts(core);
|
||||
}
|
||||
|
||||
|
||||
#if defined(CONFIG_OMAP5_DSS_HDMI_AUDIO)
|
||||
|
||||
static void hdmi5_core_audio_config(struct hdmi_core_data *core,
|
||||
struct hdmi_core_audio_config *cfg)
|
||||
{
|
||||
@ -721,7 +716,7 @@ static void hdmi5_core_audio_config(struct hdmi_core_data *core,
|
||||
|
||||
/* Source number */
|
||||
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 */
|
||||
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,
|
||||
/* only LPCM atm */
|
||||
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 */
|
||||
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,
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
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,
|
||||
struct hdmi_config *cfg);
|
||||
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,
|
||||
struct omap_dss_audio *audio, u32 pclk);
|
||||
#endif
|
||||
#endif
|
||||
|
@ -48,7 +48,6 @@ int hdmi_parse_lanes_of(struct platform_device *pdev, struct device_node *ep,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
|
||||
int hdmi_compute_acr(u32 pclk, u32 sample_freq, u32 *n, u32 *cts)
|
||||
{
|
||||
u32 deep_color;
|
||||
@ -147,4 +146,3 @@ int hdmi_compute_acr(u32 pclk, u32 sample_freq, u32 *n, u32 *cts)
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
@ -20,9 +20,7 @@
|
||||
|
||||
struct hdmi_phy_features {
|
||||
bool bist_ctrl;
|
||||
bool calc_freqout;
|
||||
bool ldo_voltage;
|
||||
unsigned long dcofreq_min;
|
||||
unsigned long max_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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@ -149,20 +148,16 @@ int hdmi_phy_configure(struct hdmi_phy_data *phy, struct hdmi_config *cfg)
|
||||
if (phy_feat->bist_ctrl)
|
||||
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 */
|
||||
u32 dco_min = phy_feat->dcofreq_min / 10;
|
||||
u32 pclk = cfg->timings.pixelclock;
|
||||
|
||||
if (pclk < dco_min)
|
||||
freqout = 0;
|
||||
else if ((pclk >= dco_min) && (pclk < phy_feat->max_phy))
|
||||
freqout = 1;
|
||||
else
|
||||
freqout = 2;
|
||||
} else {
|
||||
/*
|
||||
* If the hfbitclk != lfbitclk, it means the lfbitclk was configured
|
||||
* to be used for TMDS.
|
||||
*/
|
||||
if (hfbitclk != lfbitclk)
|
||||
freqout = 0;
|
||||
else if (hfbitclk / 10 < phy_feat->max_phy)
|
||||
freqout = 1;
|
||||
}
|
||||
else
|
||||
freqout = 2;
|
||||
|
||||
/*
|
||||
* 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)
|
||||
|
||||
static const struct hdmi_phy_features omap44xx_phy_feats = {
|
||||
.bist_ctrl = false,
|
||||
.calc_freqout = false,
|
||||
.ldo_voltage = true,
|
||||
.dcofreq_min = 500000000,
|
||||
.max_phy = 185675000,
|
||||
};
|
||||
|
||||
static const struct hdmi_phy_features omap54xx_phy_feats = {
|
||||
.bist_ctrl = true,
|
||||
.calc_freqout = true,
|
||||
.ldo_voltage = false,
|
||||
.dcofreq_min = 750000000,
|
||||
.max_phy = 186000000,
|
||||
};
|
||||
|
||||
|
@ -15,26 +15,13 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
|
||||
#include "dss.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)
|
||||
{
|
||||
#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)
|
||||
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 refclk;
|
||||
u32 mf;
|
||||
unsigned long fint, clkdco, clkout;
|
||||
unsigned long target_bitclk, target_clkdco;
|
||||
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 /= 10000;
|
||||
clkin = clk_get_rate(pll->pll.clkin);
|
||||
|
||||
/*
|
||||
* Input clock is predivided by N + 1
|
||||
* out put of which is reference clk
|
||||
*/
|
||||
DSSDBG("clkin %lu, target tmds %lu\n", clkin, target_tmds);
|
||||
|
||||
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 */
|
||||
if (pll_feat->bound_dcofreq && phy <= 65000)
|
||||
pi->regm2 = 3;
|
||||
/* adjust m2 so that the clkdco will be high enough */
|
||||
min_dco = roundup(hw->clkdco_min, fint);
|
||||
m2 = DIV_ROUND_UP(min_dco, target_bitclk);
|
||||
if (m2 == 0)
|
||||
m2 = 1;
|
||||
|
||||
target_clkdco = target_bitclk * m2;
|
||||
m = target_clkdco / fint;
|
||||
|
||||
clkdco = fint * m;
|
||||
|
||||
/* adjust clkdco with fractional mf */
|
||||
if (WARN_ON(target_clkdco - clkdco > fint))
|
||||
mf = 0;
|
||||
else
|
||||
pi->regm2 = HDMI_DEFAULT_REGM2;
|
||||
mf = (u32)div_u64(262144ull * (target_clkdco - clkdco), fint);
|
||||
|
||||
/*
|
||||
* multiplier is pixel_clk/ref_clk
|
||||
* Multiplying by 100 to avoid fractional part removal
|
||||
*/
|
||||
pi->regm = phy * pi->regm2 / refclk;
|
||||
if (mf > 0)
|
||||
clkdco += (u32)div_u64((u64)mf * fint, 262144);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
clkout = clkdco / m2;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
/* sigma-delta */
|
||||
sd = DIV_ROUND_UP(fint * m, 250000000);
|
||||
|
||||
/* Set the reference clock to sysclk reference */
|
||||
pi->refsel = HDMI_REFSEL_SYSCLK;
|
||||
DSSDBG("N = %u, M = %u, M.f = %u, M2 = %u, SD = %u\n",
|
||||
n, m, mf, m2, sd);
|
||||
DSSDBG("Fint %lu, clkdco %lu, clkout %lu\n", fint, clkdco, clkout);
|
||||
|
||||
DSSDBG("M = %d Mf = %d\n", pi->regm, pi->regmf);
|
||||
DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd);
|
||||
pi->n = n;
|
||||
pi->m = m;
|
||||
pi->mf = mf;
|
||||
pi->mX[0] = m2;
|
||||
pi->sd = sd;
|
||||
|
||||
pi->fint = fint;
|
||||
pi->clkdco = clkdco;
|
||||
pi->clkout[0] = clkout;
|
||||
}
|
||||
|
||||
|
||||
static int hdmi_pll_config(struct hdmi_pll_data *pll)
|
||||
{
|
||||
u32 r;
|
||||
struct hdmi_pll_info *fmt = &pll->info;
|
||||
|
||||
/* PLL start always use manual mode */
|
||||
REG_FLD_MOD(pll->base, PLLCTRL_PLL_CONTROL, 0x0, 0, 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
|
||||
r = FLD_MOD(r, 0x2, 3, 1); /* 500MHz and 1000MHz */
|
||||
|
||||
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);
|
||||
r = FLD_MOD(r, fmt->regm2, 24, 18);
|
||||
r = FLD_MOD(r, fmt->regmf, 17, 0);
|
||||
hdmi_write_reg(pll->base, PLLCTRL_CFG4, r);
|
||||
|
||||
/* go now */
|
||||
REG_FLD_MOD(pll->base, PLLCTRL_PLL_GO, 0x1, 0, 0);
|
||||
|
||||
/* wait for bit change */
|
||||
if (hdmi_wait_for_bit_change(pll->base, PLLCTRL_PLL_GO,
|
||||
0, 0, 0) != 0) {
|
||||
DSSERR("PLL GO bit not clearing\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/* Wait till the lock bit is set in PLL status */
|
||||
if (hdmi_wait_for_bit_change(pll->base,
|
||||
PLLCTRL_PLL_STATUS, 1, 1, 1) != 1) {
|
||||
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");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hdmi_pll_reset(struct hdmi_pll_data *pll)
|
||||
{
|
||||
/* 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)
|
||||
static int hdmi_pll_enable(struct dss_pll *dsspll)
|
||||
{
|
||||
struct hdmi_pll_data *pll = container_of(dsspll, struct hdmi_pll_data, pll);
|
||||
struct hdmi_wp_data *wp = pll->wp;
|
||||
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);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = hdmi_pll_reset(pll);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = hdmi_pll_config(pll);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static const struct hdmi_pll_features omap44xx_pll_feats = {
|
||||
.sys_reset = false,
|
||||
.bound_dcofreq = false,
|
||||
.fint_min = 500000,
|
||||
.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 dss_pll_ops dsi_pll_ops = {
|
||||
.enable = hdmi_pll_enable,
|
||||
.disable = hdmi_pll_disable,
|
||||
.set_config = dss_pll_write_config_type_b,
|
||||
};
|
||||
|
||||
static const struct hdmi_pll_features omap54xx_pll_feats = {
|
||||
.sys_reset = true,
|
||||
.bound_dcofreq = true,
|
||||
.fint_min = 620000,
|
||||
.fint_max = 2500000,
|
||||
.regm_max = 2046,
|
||||
.dcofreq_low_min = 750000000,
|
||||
.dcofreq_low_max = 1500000000,
|
||||
.dcofreq_high_min = 1250000000,
|
||||
.dcofreq_high_max = 2500000000UL,
|
||||
static const struct dss_pll_hw dss_omap4_hdmi_pll_hw = {
|
||||
.n_max = 255,
|
||||
.m_min = 20,
|
||||
.m_max = 4095,
|
||||
.mX_max = 127,
|
||||
.fint_min = 500000,
|
||||
.fint_max = 2500000,
|
||||
.clkdco_max = 1800000000,
|
||||
|
||||
.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;
|
||||
const struct hdmi_pll_features *src;
|
||||
struct dss_pll *pll = &hpll->pll;
|
||||
struct clk *clk;
|
||||
int r;
|
||||
|
||||
dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL);
|
||||
if (!dst) {
|
||||
dev_err(&pdev->dev, "Failed to allocate HDMI PHY Features\n");
|
||||
return -ENOMEM;
|
||||
clk = devm_clk_get(&pdev->dev, "sys_clk");
|
||||
if (IS_ERR(clk)) {
|
||||
DSSERR("can't get sys_clk\n");
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
|
||||
pll->name = "hdmi";
|
||||
pll->base = hpll->base;
|
||||
pll->clkin = clk;
|
||||
|
||||
switch (omapdss_get_version()) {
|
||||
case OMAPDSS_VER_OMAP4430_ES1:
|
||||
case OMAPDSS_VER_OMAP4430_ES2:
|
||||
case OMAPDSS_VER_OMAP4:
|
||||
src = &omap44xx_pll_feats;
|
||||
pll->hw = &dss_omap4_hdmi_pll_hw;
|
||||
break;
|
||||
|
||||
case OMAPDSS_VER_OMAP5:
|
||||
src = &omap54xx_pll_feats;
|
||||
pll->hw = &dss_omap5_hdmi_pll_hw;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
memcpy(dst, src, sizeof(*dst));
|
||||
pll_feat = dst;
|
||||
pll->ops = &dsi_pll_ops;
|
||||
|
||||
r = dss_pll_register(pll);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
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;
|
||||
struct resource *res;
|
||||
|
||||
r = hdmi_pll_init_features(pdev);
|
||||
if (r)
|
||||
return r;
|
||||
pll->wp = wp;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll");
|
||||
if (!res) {
|
||||
@ -286,5 +234,18 @@ int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll)
|
||||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
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,
|
||||
struct hdmi_audio_format *aud_fmt)
|
||||
{
|
||||
@ -194,8 +193,12 @@ void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp,
|
||||
DSSDBG("Enter hdmi_wp_audio_config_format\n");
|
||||
|
||||
r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CFG);
|
||||
r = FLD_MOD(r, aud_fmt->stereo_channels, 26, 24);
|
||||
r = FLD_MOD(r, aud_fmt->active_chnnls_msk, 23, 16);
|
||||
if (omapdss_get_version() == OMAPDSS_VER_OMAP4430_ES1 ||
|
||||
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->type, 4, 4);
|
||||
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)
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
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");
|
||||
return -EINVAL;
|
||||
}
|
||||
wp->phys_base = res->start;
|
||||
|
||||
wp->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(wp->base)) {
|
||||
@ -256,3 +259,8 @@ int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp)
|
||||
|
||||
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 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
|
||||
@ -131,18 +132,30 @@ struct omap_dss_device *omap_dss_find_output(const char *name)
|
||||
}
|
||||
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;
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
of_node_put(src_node);
|
||||
|
||||
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)
|
||||
{
|
||||
|
378
drivers/video/fbdev/omap2/dss/pll.c
Normal file
378
drivers/video/fbdev/omap2/dss/pll.c
Normal file
@ -0,0 +1,378 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Texas Instruments Incorporated
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define DSS_SUBSYS_NAME "PLL"
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
|
||||
#include "dss.h"
|
||||
|
||||
#define PLL_CONTROL 0x0000
|
||||
#define PLL_STATUS 0x0004
|
||||
#define PLL_GO 0x0008
|
||||
#define PLL_CONFIGURATION1 0x000C
|
||||
#define PLL_CONFIGURATION2 0x0010
|
||||
#define PLL_CONFIGURATION3 0x0014
|
||||
#define PLL_SSC_CONFIGURATION1 0x0018
|
||||
#define PLL_SSC_CONFIGURATION2 0x001C
|
||||
#define PLL_CONFIGURATION4 0x0020
|
||||
|
||||
static struct dss_pll *dss_plls[4];
|
||||
|
||||
int dss_pll_register(struct dss_pll *pll)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dss_plls); ++i) {
|
||||
if (!dss_plls[i]) {
|
||||
dss_plls[i] = pll;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
void dss_pll_unregister(struct dss_pll *pll)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dss_plls); ++i) {
|
||||
if (dss_plls[i] == pll) {
|
||||
dss_plls[i] = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct dss_pll *dss_pll_find(const char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dss_plls); ++i) {
|
||||
if (dss_plls[i] && strcmp(dss_plls[i]->name, name) == 0)
|
||||
return dss_plls[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int dss_pll_enable(struct dss_pll *pll)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = clk_prepare_enable(pll->clkin);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (pll->regulator) {
|
||||
r = regulator_enable(pll->regulator);
|
||||
if (r)
|
||||
goto err_reg;
|
||||
}
|
||||
|
||||
r = pll->ops->enable(pll);
|
||||
if (r)
|
||||
goto err_enable;
|
||||
|
||||
return 0;
|
||||
|
||||
err_enable:
|
||||
regulator_disable(pll->regulator);
|
||||
err_reg:
|
||||
clk_disable_unprepare(pll->clkin);
|
||||
return r;
|
||||
}
|
||||
|
||||
void dss_pll_disable(struct dss_pll *pll)
|
||||
{
|
||||
pll->ops->disable(pll);
|
||||
|
||||
if (pll->regulator)
|
||||
regulator_disable(pll->regulator);
|
||||
|
||||
clk_disable_unprepare(pll->clkin);
|
||||
|
||||
memset(&pll->cinfo, 0, sizeof(pll->cinfo));
|
||||
}
|
||||
|
||||
int dss_pll_set_config(struct dss_pll *pll, const struct dss_pll_clock_info *cinfo)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = pll->ops->set_config(pll, cinfo);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
pll->cinfo = *cinfo;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
const struct dss_pll_hw *hw = pll->hw;
|
||||
int m, m_start, m_stop;
|
||||
unsigned long out;
|
||||
|
||||
out_min = out_min ? out_min : 1;
|
||||
out_max = out_max ? out_max : ULONG_MAX;
|
||||
|
||||
m_start = max(DIV_ROUND_UP(clkdco, out_max), 1ul);
|
||||
|
||||
m_stop = min((unsigned)(clkdco / out_min), hw->mX_max);
|
||||
|
||||
for (m = m_start; m <= m_stop; ++m) {
|
||||
out = clkdco / m;
|
||||
|
||||
if (func(m, out, data))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
const struct dss_pll_hw *hw = pll->hw;
|
||||
int n, n_start, n_stop;
|
||||
int m, m_start, m_stop;
|
||||
unsigned long fint, clkdco;
|
||||
unsigned long pll_hw_max;
|
||||
unsigned long fint_hw_min, fint_hw_max;
|
||||
|
||||
pll_hw_max = hw->clkdco_max;
|
||||
|
||||
fint_hw_min = hw->fint_min;
|
||||
fint_hw_max = hw->fint_max;
|
||||
|
||||
n_start = max(DIV_ROUND_UP(clkin, fint_hw_max), 1ul);
|
||||
n_stop = min((unsigned)(clkin / fint_hw_min), hw->n_max);
|
||||
|
||||
pll_max = pll_max ? pll_max : ULONG_MAX;
|
||||
|
||||
for (n = n_start; n <= n_stop; ++n) {
|
||||
fint = clkin / n;
|
||||
|
||||
m_start = max(DIV_ROUND_UP(DIV_ROUND_UP(pll_min, fint), 2),
|
||||
1ul);
|
||||
m_stop = min3((unsigned)(pll_max / fint / 2),
|
||||
(unsigned)(pll_hw_max / fint / 2),
|
||||
hw->m_max);
|
||||
|
||||
for (m = m_start; m <= m_stop; ++m) {
|
||||
clkdco = 2 * m * fint;
|
||||
|
||||
if (func(n, m, fint, clkdco, data))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int wait_for_bit_change(void __iomem *reg, int bitnum, int value)
|
||||
{
|
||||
unsigned long timeout;
|
||||
ktime_t wait;
|
||||
int t;
|
||||
|
||||
/* first busyloop to see if the bit changes right away */
|
||||
t = 100;
|
||||
while (t-- > 0) {
|
||||
if (FLD_GET(readl_relaxed(reg), bitnum, bitnum) == value)
|
||||
return value;
|
||||
}
|
||||
|
||||
/* then loop for 500ms, sleeping for 1ms in between */
|
||||
timeout = jiffies + msecs_to_jiffies(500);
|
||||
while (time_before(jiffies, timeout)) {
|
||||
if (FLD_GET(readl_relaxed(reg), bitnum, bitnum) == value)
|
||||
return value;
|
||||
|
||||
wait = ns_to_ktime(1000 * 1000);
|
||||
set_current_state(TASK_UNINTERRUPTIBLE);
|
||||
schedule_hrtimeout(&wait, HRTIMER_MODE_REL);
|
||||
}
|
||||
|
||||
return !value;
|
||||
}
|
||||
|
||||
static int dss_wait_hsdiv_ack(struct dss_pll *pll, u32 hsdiv_ack_mask)
|
||||
{
|
||||
int t = 100;
|
||||
|
||||
while (t-- > 0) {
|
||||
u32 v = readl_relaxed(pll->base + PLL_STATUS);
|
||||
v &= hsdiv_ack_mask;
|
||||
if (v == hsdiv_ack_mask)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
int dss_pll_write_config_type_a(struct dss_pll *pll,
|
||||
const struct dss_pll_clock_info *cinfo)
|
||||
{
|
||||
const struct dss_pll_hw *hw = pll->hw;
|
||||
void __iomem *base = pll->base;
|
||||
int r = 0;
|
||||
u32 l;
|
||||
|
||||
l = 0;
|
||||
if (hw->has_stopmode)
|
||||
l = FLD_MOD(l, 1, 0, 0); /* PLL_STOPMODE */
|
||||
l = FLD_MOD(l, cinfo->n - 1, hw->n_msb, hw->n_lsb); /* PLL_REGN */
|
||||
l = FLD_MOD(l, cinfo->m, hw->m_msb, hw->m_lsb); /* PLL_REGM */
|
||||
/* M4 */
|
||||
l = FLD_MOD(l, cinfo->mX[0] ? cinfo->mX[0] - 1 : 0,
|
||||
hw->mX_msb[0], hw->mX_lsb[0]);
|
||||
/* M5 */
|
||||
l = FLD_MOD(l, cinfo->mX[1] ? cinfo->mX[1] - 1 : 0,
|
||||
hw->mX_msb[1], hw->mX_lsb[1]);
|
||||
writel_relaxed(l, base + PLL_CONFIGURATION1);
|
||||
|
||||
l = 0;
|
||||
/* M6 */
|
||||
l = FLD_MOD(l, cinfo->mX[2] ? cinfo->mX[2] - 1 : 0,
|
||||
hw->mX_msb[2], hw->mX_lsb[2]);
|
||||
/* M7 */
|
||||
l = FLD_MOD(l, cinfo->mX[3] ? cinfo->mX[3] - 1 : 0,
|
||||
hw->mX_msb[3], hw->mX_lsb[3]);
|
||||
writel_relaxed(l, base + PLL_CONFIGURATION3);
|
||||
|
||||
l = readl_relaxed(base + PLL_CONFIGURATION2);
|
||||
if (hw->has_freqsel) {
|
||||
u32 f = cinfo->fint < 1000000 ? 0x3 :
|
||||
cinfo->fint < 1250000 ? 0x4 :
|
||||
cinfo->fint < 1500000 ? 0x5 :
|
||||
cinfo->fint < 1750000 ? 0x6 :
|
||||
0x7;
|
||||
|
||||
l = FLD_MOD(l, f, 4, 1); /* PLL_FREQSEL */
|
||||
} else if (hw->has_selfreqdco) {
|
||||
u32 f = cinfo->clkdco < hw->clkdco_low ? 0x2 : 0x4;
|
||||
|
||||
l = FLD_MOD(l, f, 3, 1); /* PLL_SELFREQDCO */
|
||||
}
|
||||
l = FLD_MOD(l, 1, 13, 13); /* PLL_REFEN */
|
||||
l = FLD_MOD(l, 0, 14, 14); /* PHY_CLKINEN */
|
||||
l = FLD_MOD(l, 0, 16, 16); /* M4_CLOCK_EN */
|
||||
l = FLD_MOD(l, 0, 18, 18); /* M5_CLOCK_EN */
|
||||
l = FLD_MOD(l, 1, 20, 20); /* HSDIVBYPASS */
|
||||
if (hw->has_refsel)
|
||||
l = FLD_MOD(l, 3, 22, 21); /* REFSEL = sysclk */
|
||||
l = FLD_MOD(l, 0, 23, 23); /* M6_CLOCK_EN */
|
||||
l = FLD_MOD(l, 0, 25, 25); /* M7_CLOCK_EN */
|
||||
writel_relaxed(l, base + PLL_CONFIGURATION2);
|
||||
|
||||
writel_relaxed(1, base + PLL_GO); /* PLL_GO */
|
||||
|
||||
if (wait_for_bit_change(base + PLL_GO, 0, 0) != 0) {
|
||||
DSSERR("DSS DPLL GO bit not going down.\n");
|
||||
r = -EIO;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (wait_for_bit_change(base + PLL_STATUS, 1, 1) != 1) {
|
||||
DSSERR("cannot lock DSS DPLL\n");
|
||||
r = -EIO;
|
||||
goto err;
|
||||
}
|
||||
|
||||
l = readl_relaxed(base + PLL_CONFIGURATION2);
|
||||
l = FLD_MOD(l, 1, 14, 14); /* PHY_CLKINEN */
|
||||
l = FLD_MOD(l, cinfo->mX[0] ? 1 : 0, 16, 16); /* M4_CLOCK_EN */
|
||||
l = FLD_MOD(l, cinfo->mX[1] ? 1 : 0, 18, 18); /* M5_CLOCK_EN */
|
||||
l = FLD_MOD(l, 0, 20, 20); /* HSDIVBYPASS */
|
||||
l = FLD_MOD(l, cinfo->mX[2] ? 1 : 0, 23, 23); /* M6_CLOCK_EN */
|
||||
l = FLD_MOD(l, cinfo->mX[3] ? 1 : 0, 25, 25); /* M7_CLOCK_EN */
|
||||
writel_relaxed(l, base + PLL_CONFIGURATION2);
|
||||
|
||||
r = dss_wait_hsdiv_ack(pll,
|
||||
(cinfo->mX[0] ? BIT(7) : 0) |
|
||||
(cinfo->mX[1] ? BIT(8) : 0) |
|
||||
(cinfo->mX[2] ? BIT(10) : 0) |
|
||||
(cinfo->mX[3] ? BIT(11) : 0));
|
||||
if (r) {
|
||||
DSSERR("failed to enable HSDIV clocks\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
err:
|
||||
return r;
|
||||
}
|
||||
|
||||
int dss_pll_write_config_type_b(struct dss_pll *pll,
|
||||
const struct dss_pll_clock_info *cinfo)
|
||||
{
|
||||
const struct dss_pll_hw *hw = pll->hw;
|
||||
void __iomem *base = pll->base;
|
||||
u32 l;
|
||||
|
||||
l = 0;
|
||||
l = FLD_MOD(l, cinfo->m, 20, 9); /* PLL_REGM */
|
||||
l = FLD_MOD(l, cinfo->n - 1, 8, 1); /* PLL_REGN */
|
||||
writel_relaxed(l, base + PLL_CONFIGURATION1);
|
||||
|
||||
l = readl_relaxed(base + PLL_CONFIGURATION2);
|
||||
l = FLD_MOD(l, 0x0, 12, 12); /* PLL_HIGHFREQ divide by 2 */
|
||||
l = FLD_MOD(l, 0x1, 13, 13); /* PLL_REFEN */
|
||||
l = FLD_MOD(l, 0x0, 14, 14); /* PHY_CLKINEN */
|
||||
if (hw->has_refsel)
|
||||
l = FLD_MOD(l, 0x3, 22, 21); /* REFSEL = SYSCLK */
|
||||
|
||||
/* PLL_SELFREQDCO */
|
||||
if (cinfo->clkdco > hw->clkdco_low)
|
||||
l = FLD_MOD(l, 0x4, 3, 1);
|
||||
else
|
||||
l = FLD_MOD(l, 0x2, 3, 1);
|
||||
writel_relaxed(l, base + PLL_CONFIGURATION2);
|
||||
|
||||
l = readl_relaxed(base + PLL_CONFIGURATION3);
|
||||
l = FLD_MOD(l, cinfo->sd, 17, 10); /* PLL_REGSD */
|
||||
writel_relaxed(l, base + PLL_CONFIGURATION3);
|
||||
|
||||
l = readl_relaxed(base + PLL_CONFIGURATION4);
|
||||
l = FLD_MOD(l, cinfo->mX[0], 24, 18); /* PLL_REGM2 */
|
||||
l = FLD_MOD(l, cinfo->mf, 17, 0); /* PLL_REGM_F */
|
||||
writel_relaxed(l, base + PLL_CONFIGURATION4);
|
||||
|
||||
writel_relaxed(1, base + PLL_GO); /* PLL_GO */
|
||||
|
||||
if (wait_for_bit_change(base + PLL_GO, 0, 0) != 0) {
|
||||
DSSERR("DSS DPLL GO bit not going down.\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (wait_for_bit_change(base + PLL_STATUS, 1, 1) != 1) {
|
||||
DSSERR("cannot lock DSS DPLL\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -425,7 +425,7 @@ int __init sdi_init_port(struct platform_device *pdev, struct device_node *port)
|
||||
return r;
|
||||
}
|
||||
|
||||
void __exit sdi_uninit_port(void)
|
||||
void __exit sdi_uninit_port(struct device_node *port)
|
||||
{
|
||||
if (!sdi.port_initialized)
|
||||
return;
|
||||
|
@ -1182,7 +1182,7 @@ static int s3_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
|
||||
pcibios_bus_to_resource(dev->bus, &vga_res, &bus_reg);
|
||||
|
||||
par->state.vgabase = (void __iomem *) vga_res.start;
|
||||
par->state.vgabase = (void __iomem *) (unsigned long) vga_res.start;
|
||||
|
||||
/* Unlock regs */
|
||||
cr38 = vga_rcrt(par->state.vgabase, 0x38);
|
||||
|
@ -2181,8 +2181,7 @@ sh_mobile_lcdc_channel_fb_cleanup(struct sh_mobile_lcdc_chan *ch)
|
||||
if (!info || !info->device)
|
||||
return;
|
||||
|
||||
if (ch->sglist)
|
||||
vfree(ch->sglist);
|
||||
vfree(ch->sglist);
|
||||
|
||||
fb_dealloc_cmap(&info->cmap);
|
||||
framebuffer_release(info);
|
||||
|
@ -26,6 +26,8 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_data/simplefb.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
static struct fb_fix_screeninfo simplefb_fix = {
|
||||
.id = "simple",
|
||||
@ -41,6 +43,8 @@ static struct fb_var_screeninfo simplefb_var = {
|
||||
.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,
|
||||
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,
|
||||
u32 cb = blue >> (16 - info->var.blue.length);
|
||||
u32 value;
|
||||
|
||||
if (regno >= 16)
|
||||
if (regno >= PSEUDO_PALETTE_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
value = (cr << info->var.red.offset) |
|
||||
@ -163,11 +167,113 @@ static int simplefb_parse_pd(struct platform_device *pdev,
|
||||
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)
|
||||
{
|
||||
int ret;
|
||||
struct simplefb_params params;
|
||||
struct fb_info *info;
|
||||
struct simplefb_par *par;
|
||||
struct resource *mem;
|
||||
|
||||
if (fb_get_options("simplefb", NULL))
|
||||
@ -188,11 +294,13 @@ static int simplefb_probe(struct platform_device *pdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
info = framebuffer_alloc(sizeof(u32) * 16, &pdev->dev);
|
||||
info = framebuffer_alloc(sizeof(struct simplefb_par), &pdev->dev);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
platform_set_drvdata(pdev, info);
|
||||
|
||||
par = info->par;
|
||||
|
||||
info->fix = simplefb_fix;
|
||||
info->fix.smem_start = mem->start;
|
||||
info->fix.smem_len = resource_size(mem);
|
||||
@ -211,8 +319,8 @@ static int simplefb_probe(struct platform_device *pdev)
|
||||
|
||||
info->apertures = alloc_apertures(1);
|
||||
if (!info->apertures) {
|
||||
framebuffer_release(info);
|
||||
return -ENOMEM;
|
||||
ret = -ENOMEM;
|
||||
goto error_fb_release;
|
||||
}
|
||||
info->apertures->ranges[0].base = info->fix.smem_start;
|
||||
info->apertures->ranges[0].size = info->fix.smem_len;
|
||||
@ -222,10 +330,14 @@ static int simplefb_probe(struct platform_device *pdev)
|
||||
info->screen_base = ioremap_wc(info->fix.smem_start,
|
||||
info->fix.smem_len);
|
||||
if (!info->screen_base) {
|
||||
framebuffer_release(info);
|
||||
return -ENODEV;
|
||||
ret = -ENOMEM;
|
||||
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",
|
||||
info->fix.smem_start, info->fix.smem_len,
|
||||
@ -238,21 +350,29 @@ static int simplefb_probe(struct platform_device *pdev)
|
||||
ret = register_framebuffer(info);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Unable to register simplefb: %d\n", ret);
|
||||
iounmap(info->screen_base);
|
||||
framebuffer_release(info);
|
||||
return ret;
|
||||
goto error_clocks;
|
||||
}
|
||||
|
||||
dev_info(&pdev->dev, "fb%d: simplefb registered!\n", info->node);
|
||||
|
||||
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)
|
||||
{
|
||||
struct fb_info *info = platform_get_drvdata(pdev);
|
||||
struct simplefb_par *par = info->par;
|
||||
|
||||
unregister_framebuffer(info);
|
||||
simplefb_clocks_destroy(par);
|
||||
framebuffer_release(info);
|
||||
|
||||
return 0;
|
||||
@ -273,7 +393,27 @@ static struct platform_driver simplefb_driver = {
|
||||
.probe = simplefb_probe,
|
||||
.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_DESCRIPTION("Simple framebuffer driver");
|
||||
|
@ -5989,7 +5989,7 @@ static int sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
|
||||
if(!ivideo->sisvga_enabled) {
|
||||
if(pci_enable_device(pdev)) {
|
||||
if(ivideo->nbridge) pci_dev_put(ivideo->nbridge);
|
||||
pci_dev_put(ivideo->nbridge);
|
||||
framebuffer_release(sis_fb_info);
|
||||
return -EIO;
|
||||
}
|
||||
@ -6202,10 +6202,8 @@ error_0: iounmap(ivideo->video_vbase);
|
||||
error_1: release_mem_region(ivideo->video_base, ivideo->video_size);
|
||||
error_2: release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
|
||||
error_3: vfree(ivideo->bios_abase);
|
||||
if(ivideo->lpcdev)
|
||||
pci_dev_put(ivideo->lpcdev);
|
||||
if(ivideo->nbridge)
|
||||
pci_dev_put(ivideo->nbridge);
|
||||
pci_dev_put(ivideo->lpcdev);
|
||||
pci_dev_put(ivideo->nbridge);
|
||||
if(!ivideo->sisvga_enabled)
|
||||
pci_disable_device(pdev);
|
||||
framebuffer_release(sis_fb_info);
|
||||
@ -6505,11 +6503,9 @@ static void sisfb_remove(struct pci_dev *pdev)
|
||||
|
||||
vfree(ivideo->bios_abase);
|
||||
|
||||
if(ivideo->lpcdev)
|
||||
pci_dev_put(ivideo->lpcdev);
|
||||
pci_dev_put(ivideo->lpcdev);
|
||||
|
||||
if(ivideo->nbridge)
|
||||
pci_dev_put(ivideo->nbridge);
|
||||
pci_dev_put(ivideo->nbridge);
|
||||
|
||||
#ifdef CONFIG_MTRR
|
||||
/* Release MTRR region */
|
||||
|
@ -1988,6 +1988,7 @@ static int sm501fb_probe(struct platform_device *pdev)
|
||||
if (info->fb[HEAD_PANEL] == NULL &&
|
||||
info->fb[HEAD_CRT] == NULL) {
|
||||
dev_err(dev, "no framebuffers found\n");
|
||||
ret = -ENODEV;
|
||||
goto err_alloc;
|
||||
}
|
||||
|
||||
|
@ -1142,8 +1142,7 @@ static void ufx_free_framebuffer_work(struct work_struct *work)
|
||||
fb_dealloc_cmap(&info->cmap);
|
||||
if (info->monspecs.modedb)
|
||||
fb_destroy_modedb(info->monspecs.modedb);
|
||||
if (info->screen_base)
|
||||
vfree(info->screen_base);
|
||||
vfree(info->screen_base);
|
||||
|
||||
fb_destroy_modelist(&info->modelist);
|
||||
|
||||
@ -1743,8 +1742,7 @@ static int ufx_usb_probe(struct usb_interface *interface,
|
||||
fb_dealloc_cmap(&info->cmap);
|
||||
if (info->monspecs.modedb)
|
||||
fb_destroy_modedb(info->monspecs.modedb);
|
||||
if (info->screen_base)
|
||||
vfree(info->screen_base);
|
||||
vfree(info->screen_base);
|
||||
|
||||
fb_destroy_modelist(&info->modelist);
|
||||
|
||||
|
@ -922,8 +922,7 @@ static void dlfb_free(struct kref *kref)
|
||||
{
|
||||
struct dlfb_data *dev = container_of(kref, struct dlfb_data, kref);
|
||||
|
||||
if (dev->backing_buffer)
|
||||
vfree(dev->backing_buffer);
|
||||
vfree(dev->backing_buffer);
|
||||
|
||||
kfree(dev->edid);
|
||||
|
||||
@ -953,8 +952,7 @@ static void dlfb_free_framebuffer(struct dlfb_data *dev)
|
||||
fb_dealloc_cmap(&info->cmap);
|
||||
if (info->monspecs.modedb)
|
||||
fb_destroy_modedb(info->monspecs.modedb);
|
||||
if (info->screen_base)
|
||||
vfree(info->screen_base);
|
||||
vfree(info->screen_base);
|
||||
|
||||
fb_destroy_modelist(&info->modelist);
|
||||
|
||||
@ -1203,8 +1201,7 @@ static int dlfb_realloc_framebuffer(struct dlfb_data *dev, struct fb_info *info)
|
||||
if (!new_back)
|
||||
pr_info("No shadow/backing buffer allocated\n");
|
||||
else {
|
||||
if (dev->backing_buffer)
|
||||
vfree(dev->backing_buffer);
|
||||
vfree(dev->backing_buffer);
|
||||
dev->backing_buffer = new_back;
|
||||
}
|
||||
}
|
||||
|
@ -1219,8 +1219,7 @@ static int uvesafb_release(struct fb_info *info, int user)
|
||||
uvesafb_vbe_state_restore(par, par->vbe_state_orig);
|
||||
out:
|
||||
atomic_dec(&par->ref_count);
|
||||
if (task)
|
||||
uvesafb_free(task);
|
||||
uvesafb_free(task);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1923,8 +1922,7 @@ static int uvesafb_init(void)
|
||||
err = -ENOMEM;
|
||||
|
||||
if (err) {
|
||||
if (uvesafb_device)
|
||||
platform_device_put(uvesafb_device);
|
||||
platform_device_put(uvesafb_device);
|
||||
platform_driver_unregister(&uvesafb_driver);
|
||||
cn_del_callback(&uvesafb_cn_id);
|
||||
return err;
|
||||
|
@ -1937,8 +1937,7 @@ int via_fb_pci_probe(struct viafb_dev *vdev)
|
||||
out_dealloc_cmap:
|
||||
fb_dealloc_cmap(&viafbinfo->cmap);
|
||||
out_fb1_release:
|
||||
if (viafbinfo1)
|
||||
framebuffer_release(viafbinfo1);
|
||||
framebuffer_release(viafbinfo1);
|
||||
out_fb_release:
|
||||
i2c_bus_free(viaparinfo->shared);
|
||||
framebuffer_release(viafbinfo);
|
||||
|
@ -731,7 +731,7 @@ static int vt8623_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
|
||||
|
||||
pcibios_bus_to_resource(dev->bus, &vga_res, &bus_reg);
|
||||
|
||||
par->state.vgabase = (void __iomem *) vga_res.start;
|
||||
par->state.vgabase = (void __iomem *) (unsigned long) vga_res.start;
|
||||
|
||||
/* Find how many physical memory there is on card */
|
||||
memsize1 = (vga_rseq(par->state.vgabase, 0x34) + 1) >> 1;
|
||||
|
@ -108,8 +108,6 @@ static inline struct device_node *of_node_get(struct device_node *node)
|
||||
static inline void of_node_put(struct device_node *node) { }
|
||||
#endif /* !CONFIG_OF_DYNAMIC */
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
|
||||
/* Pointer for first entry in chain of all nodes. */
|
||||
extern struct device_node *of_allnodes;
|
||||
extern struct device_node *of_chosen;
|
||||
@ -117,6 +115,7 @@ extern struct device_node *of_aliases;
|
||||
extern struct device_node *of_stdout;
|
||||
extern raw_spinlock_t devtree_lock;
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static inline bool is_of_node(struct fwnode_handle *fwnode)
|
||||
{
|
||||
return fwnode && fwnode->type == FWNODE_OF;
|
||||
|
43
include/sound/omap-hdmi-audio.h
Normal file
43
include/sound/omap-hdmi-audio.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* hdmi-audio.c -- OMAP4+ DSS HDMI audio support library
|
||||
*
|
||||
* Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com
|
||||
*
|
||||
* Author: Jyri Sarha <jsarha@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <video/omapdss.h>
|
||||
|
||||
#ifndef __OMAP_HDMI_AUDIO_H__
|
||||
#define __OMAP_HDMI_AUDIO_H__
|
||||
|
||||
struct omap_hdmi_audio_ops {
|
||||
int (*audio_startup)(struct device *dev,
|
||||
void (*abort_cb)(struct device *dev));
|
||||
int (*audio_shutdown)(struct device *dev);
|
||||
int (*audio_start)(struct device *dev);
|
||||
void (*audio_stop)(struct device *dev);
|
||||
int (*audio_config)(struct device *dev,
|
||||
struct omap_dss_audio *dss_audio);
|
||||
};
|
||||
|
||||
/* HDMI audio initalization data */
|
||||
struct omap_hdmi_audio_pdata {
|
||||
struct device *dev;
|
||||
enum omapdss_version dss_version;
|
||||
phys_addr_t audio_dma_addr;
|
||||
|
||||
const struct omap_hdmi_audio_ops *ops;
|
||||
};
|
||||
|
||||
#endif /* __OMAP_HDMI_AUDIO_H__ */
|
@ -166,13 +166,6 @@ enum omap_dss_display_state {
|
||||
OMAP_DSS_DISPLAY_ACTIVE,
|
||||
};
|
||||
|
||||
enum omap_dss_audio_state {
|
||||
OMAP_DSS_AUDIO_DISABLED = 0,
|
||||
OMAP_DSS_AUDIO_ENABLED,
|
||||
OMAP_DSS_AUDIO_CONFIGURED,
|
||||
OMAP_DSS_AUDIO_PLAYING,
|
||||
};
|
||||
|
||||
struct omap_dss_audio {
|
||||
struct snd_aes_iec958 *iec;
|
||||
struct snd_cea_861_aud_if *cea;
|
||||
@ -635,19 +628,6 @@ struct omapdss_hdmi_ops {
|
||||
int (*set_hdmi_mode)(struct omap_dss_device *dssdev, bool hdmi_mode);
|
||||
int (*set_infoframe)(struct omap_dss_device *dssdev,
|
||||
const struct hdmi_avi_infoframe *avi);
|
||||
|
||||
/*
|
||||
* Note: These functions might sleep. Do not call while
|
||||
* holding a spinlock/readlock.
|
||||
*/
|
||||
int (*audio_enable)(struct omap_dss_device *dssdev);
|
||||
void (*audio_disable)(struct omap_dss_device *dssdev);
|
||||
bool (*audio_supported)(struct omap_dss_device *dssdev);
|
||||
int (*audio_config)(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_audio *audio);
|
||||
/* Note: These functions may not sleep */
|
||||
int (*audio_start)(struct omap_dss_device *dssdev);
|
||||
void (*audio_stop)(struct omap_dss_device *dssdev);
|
||||
};
|
||||
|
||||
struct omapdss_dsi_ops {
|
||||
@ -783,8 +763,6 @@ struct omap_dss_device {
|
||||
|
||||
enum omap_dss_display_state state;
|
||||
|
||||
enum omap_dss_audio_state audio_state;
|
||||
|
||||
/* OMAP DSS output specific fields */
|
||||
|
||||
struct list_head list;
|
||||
@ -795,6 +773,9 @@ struct omap_dss_device {
|
||||
/* output instance */
|
||||
enum omap_dss_output_id id;
|
||||
|
||||
/* the port number in the DT node */
|
||||
int port_num;
|
||||
|
||||
/* dynamic fields */
|
||||
struct omap_overlay_manager *manager;
|
||||
|
||||
@ -858,24 +839,6 @@ struct omap_dss_driver {
|
||||
int (*set_hdmi_mode)(struct omap_dss_device *dssdev, bool hdmi_mode);
|
||||
int (*set_hdmi_infoframe)(struct omap_dss_device *dssdev,
|
||||
const struct hdmi_avi_infoframe *avi);
|
||||
|
||||
/*
|
||||
* For display drivers that support audio. This encompasses
|
||||
* HDMI and DisplayPort at the moment.
|
||||
*/
|
||||
/*
|
||||
* Note: These functions might sleep. Do not call while
|
||||
* holding a spinlock/readlock.
|
||||
*/
|
||||
int (*audio_enable)(struct omap_dss_device *dssdev);
|
||||
void (*audio_disable)(struct omap_dss_device *dssdev);
|
||||
bool (*audio_supported)(struct omap_dss_device *dssdev);
|
||||
int (*audio_config)(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_audio *audio);
|
||||
/* Note: These functions may not sleep */
|
||||
int (*audio_start)(struct omap_dss_device *dssdev);
|
||||
void (*audio_stop)(struct omap_dss_device *dssdev);
|
||||
|
||||
};
|
||||
|
||||
enum omapdss_version omapdss_get_version(void);
|
||||
@ -918,7 +881,7 @@ int omapdss_register_output(struct omap_dss_device *output);
|
||||
void omapdss_unregister_output(struct omap_dss_device *output);
|
||||
struct omap_dss_device *omap_dss_get_output(enum omap_dss_output_id id);
|
||||
struct omap_dss_device *omap_dss_find_output(const char *name);
|
||||
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);
|
||||
int omapdss_output_set_device(struct omap_dss_device *out,
|
||||
struct omap_dss_device *dssdev);
|
||||
int omapdss_output_unset_device(struct omap_dss_device *out);
|
||||
|
@ -12,8 +12,20 @@ config SND_OMAP_SOC_MCBSP
|
||||
config SND_OMAP_SOC_MCPDM
|
||||
tristate
|
||||
|
||||
config SND_OMAP_SOC_HDMI
|
||||
tristate
|
||||
config SND_OMAP_SOC_HDMI_AUDIO
|
||||
tristate "HDMI audio support for OMAP4+ based SoCs"
|
||||
depends on SND_OMAP_SOC
|
||||
help
|
||||
For HDMI audio to work OMAPDSS HDMI support should be
|
||||
enabled.
|
||||
The hdmi audio driver implements cpu-dai component using the
|
||||
callbacks provided by OMAPDSS and registers the component
|
||||
under DSS HDMI device. Omap-pcm is registered for platform
|
||||
component also under DSS HDMI device. Dummy codec is used as
|
||||
as codec component. The hdmi audio driver implements also
|
||||
the card and registers it under its own platform device.
|
||||
The device for the dirver is registered by OMAPDSS hdmi
|
||||
driver.
|
||||
|
||||
config SND_OMAP_SOC_N810
|
||||
tristate "SoC Audio support for Nokia N810"
|
||||
@ -100,16 +112,6 @@ config SND_OMAP_SOC_OMAP_ABE_TWL6040
|
||||
- PandaBoard (4430)
|
||||
- PandaBoardES (4460)
|
||||
|
||||
config SND_OMAP_SOC_OMAP_HDMI
|
||||
tristate "SoC Audio support for Texas Instruments OMAP HDMI"
|
||||
depends on SND_OMAP_SOC && OMAP4_DSS_HDMI && OMAP2_DSS
|
||||
select SND_OMAP_SOC_HDMI
|
||||
select SND_SOC_HDMI_CODEC
|
||||
select OMAP4_DSS_HDMI_AUDIO
|
||||
help
|
||||
Say Y if you want to add support for SoC HDMI audio on Texas Instruments
|
||||
OMAP4 chips
|
||||
|
||||
config SND_OMAP_SOC_OMAP3_PANDORA
|
||||
tristate "SoC Audio support for OMAP3 Pandora"
|
||||
depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP3_PANDORA
|
||||
|
@ -3,13 +3,13 @@ snd-soc-omap-objs := omap-pcm.o
|
||||
snd-soc-omap-dmic-objs := omap-dmic.o
|
||||
snd-soc-omap-mcbsp-objs := omap-mcbsp.o mcbsp.o
|
||||
snd-soc-omap-mcpdm-objs := omap-mcpdm.o
|
||||
snd-soc-omap-hdmi-objs := omap-hdmi.o
|
||||
snd-soc-omap-hdmi-audio-objs := omap-hdmi-audio.o
|
||||
|
||||
obj-$(CONFIG_SND_OMAP_SOC) += snd-soc-omap.o
|
||||
obj-$(CONFIG_SND_OMAP_SOC_DMIC) += snd-soc-omap-dmic.o
|
||||
obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o
|
||||
obj-$(CONFIG_SND_OMAP_SOC_MCPDM) += snd-soc-omap-mcpdm.o
|
||||
obj-$(CONFIG_SND_OMAP_SOC_HDMI) += snd-soc-omap-hdmi.o
|
||||
obj-$(CONFIG_SND_OMAP_SOC_HDMI_AUDIO) += snd-soc-omap-hdmi-audio.o
|
||||
|
||||
# OMAP Machine Support
|
||||
snd-soc-n810-objs := n810.o
|
||||
@ -20,7 +20,6 @@ snd-soc-am3517evm-objs := am3517evm.o
|
||||
snd-soc-omap-abe-twl6040-objs := omap-abe-twl6040.o
|
||||
snd-soc-omap-twl4030-objs := omap-twl4030.o
|
||||
snd-soc-omap3pandora-objs := omap3pandora.o
|
||||
snd-soc-omap-hdmi-card-objs := omap-hdmi-card.o
|
||||
|
||||
obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o
|
||||
obj-$(CONFIG_SND_OMAP_SOC_RX51) += snd-soc-rx51.o
|
||||
@ -30,4 +29,3 @@ obj-$(CONFIG_SND_OMAP_SOC_AM3517EVM) += snd-soc-am3517evm.o
|
||||
obj-$(CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040) += snd-soc-omap-abe-twl6040.o
|
||||
obj-$(CONFIG_SND_OMAP_SOC_OMAP_TWL4030) += snd-soc-omap-twl4030.o
|
||||
obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o
|
||||
obj-$(CONFIG_SND_OMAP_SOC_OMAP_HDMI) += snd-soc-omap-hdmi-card.o
|
||||
|
407
sound/soc/omap/omap-hdmi-audio.c
Normal file
407
sound/soc/omap/omap-hdmi-audio.c
Normal file
@ -0,0 +1,407 @@
|
||||
/*
|
||||
* omap-hdmi-audio.c -- OMAP4+ DSS HDMI audio support library
|
||||
*
|
||||
* Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com
|
||||
*
|
||||
* Author: Jyri Sarha <jsarha@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/dmaengine_pcm.h>
|
||||
#include <uapi/sound/asound.h>
|
||||
#include <sound/asoundef.h>
|
||||
#include <sound/omap-pcm.h>
|
||||
#include <sound/omap-hdmi-audio.h>
|
||||
#include <video/omapdss.h>
|
||||
|
||||
#define DRV_NAME "omap-hdmi-audio"
|
||||
|
||||
struct hdmi_audio_data {
|
||||
struct snd_soc_card *card;
|
||||
|
||||
const struct omap_hdmi_audio_ops *ops;
|
||||
struct device *dssdev;
|
||||
struct snd_dmaengine_dai_dma_data dma_data;
|
||||
struct omap_dss_audio dss_audio;
|
||||
struct snd_aes_iec958 iec;
|
||||
struct snd_cea_861_aud_if cea;
|
||||
|
||||
struct mutex current_stream_lock;
|
||||
struct snd_pcm_substream *current_stream;
|
||||
};
|
||||
|
||||
static
|
||||
struct hdmi_audio_data *card_drvdata_substream(struct snd_pcm_substream *ss)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = ss->private_data;
|
||||
|
||||
return snd_soc_card_get_drvdata(rtd->card);
|
||||
}
|
||||
|
||||
static void hdmi_dai_abort(struct device *dev)
|
||||
{
|
||||
struct hdmi_audio_data *ad = dev_get_drvdata(dev);
|
||||
|
||||
mutex_lock(&ad->current_stream_lock);
|
||||
if (ad->current_stream && ad->current_stream->runtime &&
|
||||
snd_pcm_running(ad->current_stream)) {
|
||||
dev_err(dev, "HDMI display disabled, aborting playback\n");
|
||||
snd_pcm_stream_lock_irq(ad->current_stream);
|
||||
snd_pcm_stop(ad->current_stream, SNDRV_PCM_STATE_DISCONNECTED);
|
||||
snd_pcm_stream_unlock_irq(ad->current_stream);
|
||||
}
|
||||
mutex_unlock(&ad->current_stream_lock);
|
||||
}
|
||||
|
||||
static int hdmi_dai_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct hdmi_audio_data *ad = card_drvdata_substream(substream);
|
||||
int ret;
|
||||
/*
|
||||
* Make sure that the period bytes are multiple of the DMA packet size.
|
||||
* Largest packet size we use is 32 32-bit words = 128 bytes
|
||||
*/
|
||||
ret = snd_pcm_hw_constraint_step(substream->runtime, 0,
|
||||
SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128);
|
||||
if (ret < 0) {
|
||||
dev_err(dai->dev, "could not apply constraint\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
snd_soc_dai_set_dma_data(dai, substream, &ad->dma_data);
|
||||
|
||||
mutex_lock(&ad->current_stream_lock);
|
||||
ad->current_stream = substream;
|
||||
mutex_unlock(&ad->current_stream_lock);
|
||||
|
||||
ret = ad->ops->audio_startup(ad->dssdev, hdmi_dai_abort);
|
||||
|
||||
if (ret) {
|
||||
mutex_lock(&ad->current_stream_lock);
|
||||
ad->current_stream = NULL;
|
||||
mutex_unlock(&ad->current_stream_lock);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int hdmi_dai_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct hdmi_audio_data *ad = card_drvdata_substream(substream);
|
||||
struct snd_aes_iec958 *iec = &ad->iec;
|
||||
struct snd_cea_861_aud_if *cea = &ad->cea;
|
||||
|
||||
WARN_ON(ad->current_stream != substream);
|
||||
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
ad->dma_data.maxburst = 16;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S24_LE:
|
||||
ad->dma_data.maxburst = 32;
|
||||
break;
|
||||
default:
|
||||
dev_err(dai->dev, "format not supported!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ad->dss_audio.iec = iec;
|
||||
ad->dss_audio.cea = cea;
|
||||
/*
|
||||
* fill the IEC-60958 channel status word
|
||||
*/
|
||||
/* initialize the word bytes */
|
||||
memset(iec->status, 0, sizeof(iec->status));
|
||||
|
||||
/* specify IEC-60958-3 (commercial use) */
|
||||
iec->status[0] &= ~IEC958_AES0_PROFESSIONAL;
|
||||
|
||||
/* specify that the audio is LPCM*/
|
||||
iec->status[0] &= ~IEC958_AES0_NONAUDIO;
|
||||
|
||||
iec->status[0] |= IEC958_AES0_CON_NOT_COPYRIGHT;
|
||||
|
||||
iec->status[0] |= IEC958_AES0_CON_EMPHASIS_NONE;
|
||||
|
||||
iec->status[0] |= IEC958_AES1_PRO_MODE_NOTID;
|
||||
|
||||
iec->status[1] = IEC958_AES1_CON_GENERAL;
|
||||
|
||||
iec->status[2] |= IEC958_AES2_CON_SOURCE_UNSPEC;
|
||||
|
||||
iec->status[2] |= IEC958_AES2_CON_CHANNEL_UNSPEC;
|
||||
|
||||
switch (params_rate(params)) {
|
||||
case 32000:
|
||||
iec->status[3] |= IEC958_AES3_CON_FS_32000;
|
||||
break;
|
||||
case 44100:
|
||||
iec->status[3] |= IEC958_AES3_CON_FS_44100;
|
||||
break;
|
||||
case 48000:
|
||||
iec->status[3] |= IEC958_AES3_CON_FS_48000;
|
||||
break;
|
||||
case 88200:
|
||||
iec->status[3] |= IEC958_AES3_CON_FS_88200;
|
||||
break;
|
||||
case 96000:
|
||||
iec->status[3] |= IEC958_AES3_CON_FS_96000;
|
||||
break;
|
||||
case 176400:
|
||||
iec->status[3] |= IEC958_AES3_CON_FS_176400;
|
||||
break;
|
||||
case 192000:
|
||||
iec->status[3] |= IEC958_AES3_CON_FS_192000;
|
||||
break;
|
||||
default:
|
||||
dev_err(dai->dev, "rate not supported!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* specify the clock accuracy */
|
||||
iec->status[3] |= IEC958_AES3_CON_CLOCK_1000PPM;
|
||||
|
||||
/*
|
||||
* specify the word length. The same word length value can mean
|
||||
* two different lengths. Hence, we need to specify the maximum
|
||||
* word length as well.
|
||||
*/
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
iec->status[4] |= IEC958_AES4_CON_WORDLEN_20_16;
|
||||
iec->status[4] &= ~IEC958_AES4_CON_MAX_WORDLEN_24;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S24_LE:
|
||||
iec->status[4] |= IEC958_AES4_CON_WORDLEN_24_20;
|
||||
iec->status[4] |= IEC958_AES4_CON_MAX_WORDLEN_24;
|
||||
break;
|
||||
default:
|
||||
dev_err(dai->dev, "format not supported!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill the CEA-861 audio infoframe (see spec for details)
|
||||
*/
|
||||
|
||||
cea->db1_ct_cc = (params_channels(params) - 1)
|
||||
& CEA861_AUDIO_INFOFRAME_DB1CC;
|
||||
cea->db1_ct_cc |= CEA861_AUDIO_INFOFRAME_DB1CT_FROM_STREAM;
|
||||
|
||||
cea->db2_sf_ss = CEA861_AUDIO_INFOFRAME_DB2SF_FROM_STREAM;
|
||||
cea->db2_sf_ss |= CEA861_AUDIO_INFOFRAME_DB2SS_FROM_STREAM;
|
||||
|
||||
cea->db3 = 0; /* not used, all zeros */
|
||||
|
||||
/*
|
||||
* The OMAP HDMI IP requires to use the 8-channel channel code when
|
||||
* transmitting more than two channels.
|
||||
*/
|
||||
if (params_channels(params) == 2)
|
||||
cea->db4_ca = 0x0;
|
||||
else
|
||||
cea->db4_ca = 0x13;
|
||||
|
||||
cea->db5_dminh_lsv = CEA861_AUDIO_INFOFRAME_DB5_DM_INH_PROHIBITED;
|
||||
/* the expression is trivial but makes clear what we are doing */
|
||||
cea->db5_dminh_lsv |= (0 & CEA861_AUDIO_INFOFRAME_DB5_LSV);
|
||||
|
||||
return ad->ops->audio_config(ad->dssdev, &ad->dss_audio);
|
||||
}
|
||||
|
||||
static int hdmi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct hdmi_audio_data *ad = card_drvdata_substream(substream);
|
||||
int err = 0;
|
||||
|
||||
WARN_ON(ad->current_stream != substream);
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
err = ad->ops->audio_start(ad->dssdev);
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
ad->ops->audio_stop(ad->dssdev);
|
||||
break;
|
||||
default:
|
||||
err = -EINVAL;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static void hdmi_dai_shutdown(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct hdmi_audio_data *ad = card_drvdata_substream(substream);
|
||||
|
||||
WARN_ON(ad->current_stream != substream);
|
||||
|
||||
ad->ops->audio_shutdown(ad->dssdev);
|
||||
|
||||
mutex_lock(&ad->current_stream_lock);
|
||||
ad->current_stream = NULL;
|
||||
mutex_unlock(&ad->current_stream_lock);
|
||||
}
|
||||
|
||||
static const struct snd_soc_dai_ops hdmi_dai_ops = {
|
||||
.startup = hdmi_dai_startup,
|
||||
.hw_params = hdmi_dai_hw_params,
|
||||
.trigger = hdmi_dai_trigger,
|
||||
.shutdown = hdmi_dai_shutdown,
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver omap_hdmi_component = {
|
||||
.name = "omapdss_hdmi",
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver omap5_hdmi_dai = {
|
||||
.name = "omap5-hdmi-dai",
|
||||
.playback = {
|
||||
.channels_min = 2,
|
||||
.channels_max = 8,
|
||||
.rates = (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
|
||||
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
|
||||
SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
|
||||
SNDRV_PCM_RATE_192000),
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
},
|
||||
.ops = &hdmi_dai_ops,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver omap4_hdmi_dai = {
|
||||
.name = "omap4-hdmi-dai",
|
||||
.playback = {
|
||||
.channels_min = 2,
|
||||
.channels_max = 8,
|
||||
.rates = (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
|
||||
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
|
||||
SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
|
||||
SNDRV_PCM_RATE_192000),
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
|
||||
},
|
||||
.ops = &hdmi_dai_ops,
|
||||
};
|
||||
|
||||
static int omap_hdmi_audio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_hdmi_audio_pdata *ha = pdev->dev.platform_data;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct hdmi_audio_data *ad;
|
||||
struct snd_soc_dai_driver *dai_drv;
|
||||
struct snd_soc_card *card;
|
||||
int ret;
|
||||
|
||||
if (!ha) {
|
||||
dev_err(dev, "No platform data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ad = devm_kzalloc(dev, sizeof(*ad), GFP_KERNEL);
|
||||
if (!ad)
|
||||
return -ENOMEM;
|
||||
ad->dssdev = ha->dev;
|
||||
ad->ops = ha->ops;
|
||||
ad->dma_data.addr = ha->audio_dma_addr;
|
||||
ad->dma_data.filter_data = "audio_tx";
|
||||
ad->dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
mutex_init(&ad->current_stream_lock);
|
||||
|
||||
switch (ha->dss_version) {
|
||||
case OMAPDSS_VER_OMAP4430_ES1:
|
||||
case OMAPDSS_VER_OMAP4430_ES2:
|
||||
case OMAPDSS_VER_OMAP4:
|
||||
dai_drv = &omap4_hdmi_dai;
|
||||
break;
|
||||
case OMAPDSS_VER_OMAP5:
|
||||
dai_drv = &omap5_hdmi_dai;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = snd_soc_register_component(ad->dssdev, &omap_hdmi_component,
|
||||
dai_drv, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = omap_pcm_platform_register(ad->dssdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
|
||||
card->name = devm_kasprintf(dev, GFP_KERNEL,
|
||||
"HDMI %s", dev_name(ad->dssdev));
|
||||
card->owner = THIS_MODULE;
|
||||
card->dai_link =
|
||||
devm_kzalloc(dev, sizeof(*(card->dai_link)), GFP_KERNEL);
|
||||
card->dai_link->name = card->name;
|
||||
card->dai_link->stream_name = card->name;
|
||||
card->dai_link->cpu_dai_name = dev_name(ad->dssdev);
|
||||
card->dai_link->platform_name = dev_name(ad->dssdev);
|
||||
card->dai_link->codec_name = "snd-soc-dummy";
|
||||
card->dai_link->codec_dai_name = "snd-soc-dummy-dai";
|
||||
card->num_links = 1;
|
||||
card->dev = dev;
|
||||
|
||||
ret = snd_soc_register_card(card);
|
||||
if (ret) {
|
||||
dev_err(dev, "snd_soc_register_card failed (%d)\n", ret);
|
||||
snd_soc_unregister_component(ad->dssdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ad->card = card;
|
||||
snd_soc_card_set_drvdata(card, ad);
|
||||
|
||||
dev_set_drvdata(dev, ad);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omap_hdmi_audio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct hdmi_audio_data *ad = platform_get_drvdata(pdev);
|
||||
|
||||
snd_soc_unregister_card(ad->card);
|
||||
snd_soc_unregister_component(ad->dssdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver hdmi_audio_driver = {
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = omap_hdmi_audio_probe,
|
||||
.remove = omap_hdmi_audio_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(hdmi_audio_driver);
|
||||
|
||||
MODULE_AUTHOR("Jyri Sarha <jsarha@ti.com>");
|
||||
MODULE_DESCRIPTION("OMAP HDMI Audio Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:" DRV_NAME);
|
@ -1,87 +0,0 @@
|
||||
/*
|
||||
* omap-hdmi-card.c
|
||||
*
|
||||
* OMAP ALSA SoC machine driver for TI OMAP HDMI
|
||||
* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
|
||||
* Author: Ricardo Neri <ricardo.neri@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
#include <asm/mach-types.h>
|
||||
#include <video/omapdss.h>
|
||||
|
||||
#define DRV_NAME "omap-hdmi-audio"
|
||||
|
||||
static struct snd_soc_dai_link omap_hdmi_dai = {
|
||||
.name = "HDMI",
|
||||
.stream_name = "HDMI",
|
||||
.cpu_dai_name = "omap-hdmi-audio-dai",
|
||||
.platform_name = "omap-hdmi-audio-dai",
|
||||
.codec_name = "hdmi-audio-codec",
|
||||
.codec_dai_name = "hdmi-hifi",
|
||||
};
|
||||
|
||||
static struct snd_soc_card snd_soc_omap_hdmi = {
|
||||
.name = "OMAPHDMI",
|
||||
.owner = THIS_MODULE,
|
||||
.dai_link = &omap_hdmi_dai,
|
||||
.num_links = 1,
|
||||
};
|
||||
|
||||
static int omap_hdmi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = &snd_soc_omap_hdmi;
|
||||
int ret;
|
||||
|
||||
card->dev = &pdev->dev;
|
||||
|
||||
ret = snd_soc_register_card(card);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
|
||||
card->dev = NULL;
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omap_hdmi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = platform_get_drvdata(pdev);
|
||||
|
||||
snd_soc_unregister_card(card);
|
||||
card->dev = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver omap_hdmi_driver = {
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = omap_hdmi_probe,
|
||||
.remove = omap_hdmi_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(omap_hdmi_driver);
|
||||
|
||||
MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>");
|
||||
MODULE_DESCRIPTION("OMAP HDMI machine ASoC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:" DRV_NAME);
|
@ -1,364 +0,0 @@
|
||||
/*
|
||||
* omap-hdmi.c
|
||||
*
|
||||
* OMAP ALSA SoC DAI driver for HDMI audio on OMAP4 processors.
|
||||
* Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
|
||||
* Authors: Jorge Candelaria <jorge.candelaria@ti.com>
|
||||
* Ricardo Neri <ricardo.neri@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/asound.h>
|
||||
#include <sound/asoundef.h>
|
||||
#include <sound/dmaengine_pcm.h>
|
||||
#include <video/omapdss.h>
|
||||
#include <sound/omap-pcm.h>
|
||||
|
||||
#include "omap-hdmi.h"
|
||||
|
||||
#define DRV_NAME "omap-hdmi-audio-dai"
|
||||
|
||||
struct hdmi_priv {
|
||||
struct snd_dmaengine_dai_dma_data dma_data;
|
||||
unsigned int dma_req;
|
||||
struct omap_dss_audio dss_audio;
|
||||
struct snd_aes_iec958 iec;
|
||||
struct snd_cea_861_aud_if cea;
|
||||
struct omap_dss_device *dssdev;
|
||||
};
|
||||
|
||||
static int omap_hdmi_dai_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai);
|
||||
int err;
|
||||
/*
|
||||
* Make sure that the period bytes are multiple of the DMA packet size.
|
||||
* Largest packet size we use is 32 32-bit words = 128 bytes
|
||||
*/
|
||||
err = snd_pcm_hw_constraint_step(substream->runtime, 0,
|
||||
SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128);
|
||||
if (err < 0) {
|
||||
dev_err(dai->dev, "could not apply constraint\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!priv->dssdev->driver->audio_supported(priv->dssdev)) {
|
||||
dev_err(dai->dev, "audio not supported\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
snd_soc_dai_set_dma_data(dai, substream, &priv->dma_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omap_hdmi_dai_prepare(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
return priv->dssdev->driver->audio_enable(priv->dssdev);
|
||||
}
|
||||
|
||||
static int omap_hdmi_dai_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai);
|
||||
struct snd_aes_iec958 *iec = &priv->iec;
|
||||
struct snd_cea_861_aud_if *cea = &priv->cea;
|
||||
int err = 0;
|
||||
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
priv->dma_data.maxburst = 16;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S24_LE:
|
||||
priv->dma_data.maxburst = 32;
|
||||
break;
|
||||
default:
|
||||
dev_err(dai->dev, "format not supported!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* fill the IEC-60958 channel status word
|
||||
*/
|
||||
/* initialize the word bytes */
|
||||
memset(iec->status, 0, sizeof(iec->status));
|
||||
|
||||
/* specify IEC-60958-3 (commercial use) */
|
||||
iec->status[0] &= ~IEC958_AES0_PROFESSIONAL;
|
||||
|
||||
/* specify that the audio is LPCM*/
|
||||
iec->status[0] &= ~IEC958_AES0_NONAUDIO;
|
||||
|
||||
iec->status[0] |= IEC958_AES0_CON_NOT_COPYRIGHT;
|
||||
|
||||
iec->status[0] |= IEC958_AES0_CON_EMPHASIS_NONE;
|
||||
|
||||
iec->status[0] |= IEC958_AES1_PRO_MODE_NOTID;
|
||||
|
||||
iec->status[1] = IEC958_AES1_CON_GENERAL;
|
||||
|
||||
iec->status[2] |= IEC958_AES2_CON_SOURCE_UNSPEC;
|
||||
|
||||
iec->status[2] |= IEC958_AES2_CON_CHANNEL_UNSPEC;
|
||||
|
||||
switch (params_rate(params)) {
|
||||
case 32000:
|
||||
iec->status[3] |= IEC958_AES3_CON_FS_32000;
|
||||
break;
|
||||
case 44100:
|
||||
iec->status[3] |= IEC958_AES3_CON_FS_44100;
|
||||
break;
|
||||
case 48000:
|
||||
iec->status[3] |= IEC958_AES3_CON_FS_48000;
|
||||
break;
|
||||
case 88200:
|
||||
iec->status[3] |= IEC958_AES3_CON_FS_88200;
|
||||
break;
|
||||
case 96000:
|
||||
iec->status[3] |= IEC958_AES3_CON_FS_96000;
|
||||
break;
|
||||
case 176400:
|
||||
iec->status[3] |= IEC958_AES3_CON_FS_176400;
|
||||
break;
|
||||
case 192000:
|
||||
iec->status[3] |= IEC958_AES3_CON_FS_192000;
|
||||
break;
|
||||
default:
|
||||
dev_err(dai->dev, "rate not supported!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* specify the clock accuracy */
|
||||
iec->status[3] |= IEC958_AES3_CON_CLOCK_1000PPM;
|
||||
|
||||
/*
|
||||
* specify the word length. The same word length value can mean
|
||||
* two different lengths. Hence, we need to specify the maximum
|
||||
* word length as well.
|
||||
*/
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
iec->status[4] |= IEC958_AES4_CON_WORDLEN_20_16;
|
||||
iec->status[4] &= ~IEC958_AES4_CON_MAX_WORDLEN_24;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S24_LE:
|
||||
iec->status[4] |= IEC958_AES4_CON_WORDLEN_24_20;
|
||||
iec->status[4] |= IEC958_AES4_CON_MAX_WORDLEN_24;
|
||||
break;
|
||||
default:
|
||||
dev_err(dai->dev, "format not supported!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill the CEA-861 audio infoframe (see spec for details)
|
||||
*/
|
||||
|
||||
cea->db1_ct_cc = (params_channels(params) - 1)
|
||||
& CEA861_AUDIO_INFOFRAME_DB1CC;
|
||||
cea->db1_ct_cc |= CEA861_AUDIO_INFOFRAME_DB1CT_FROM_STREAM;
|
||||
|
||||
cea->db2_sf_ss = CEA861_AUDIO_INFOFRAME_DB2SF_FROM_STREAM;
|
||||
cea->db2_sf_ss |= CEA861_AUDIO_INFOFRAME_DB2SS_FROM_STREAM;
|
||||
|
||||
cea->db3 = 0; /* not used, all zeros */
|
||||
|
||||
/*
|
||||
* The OMAP HDMI IP requires to use the 8-channel channel code when
|
||||
* transmitting more than two channels.
|
||||
*/
|
||||
if (params_channels(params) == 2)
|
||||
cea->db4_ca = 0x0;
|
||||
else
|
||||
cea->db4_ca = 0x13;
|
||||
|
||||
cea->db5_dminh_lsv = CEA861_AUDIO_INFOFRAME_DB5_DM_INH_PROHIBITED;
|
||||
/* the expression is trivial but makes clear what we are doing */
|
||||
cea->db5_dminh_lsv |= (0 & CEA861_AUDIO_INFOFRAME_DB5_LSV);
|
||||
|
||||
priv->dss_audio.iec = iec;
|
||||
priv->dss_audio.cea = cea;
|
||||
|
||||
err = priv->dssdev->driver->audio_config(priv->dssdev,
|
||||
&priv->dss_audio);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int omap_hdmi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai);
|
||||
int err = 0;
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
err = priv->dssdev->driver->audio_start(priv->dssdev);
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
priv->dssdev->driver->audio_stop(priv->dssdev);
|
||||
break;
|
||||
default:
|
||||
err = -EINVAL;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static void omap_hdmi_dai_shutdown(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai);
|
||||
|
||||
priv->dssdev->driver->audio_disable(priv->dssdev);
|
||||
}
|
||||
|
||||
static const struct snd_soc_dai_ops omap_hdmi_dai_ops = {
|
||||
.startup = omap_hdmi_dai_startup,
|
||||
.hw_params = omap_hdmi_dai_hw_params,
|
||||
.prepare = omap_hdmi_dai_prepare,
|
||||
.trigger = omap_hdmi_dai_trigger,
|
||||
.shutdown = omap_hdmi_dai_shutdown,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver omap_hdmi_dai = {
|
||||
.playback = {
|
||||
.channels_min = 2,
|
||||
.channels_max = 8,
|
||||
.rates = OMAP_HDMI_RATES,
|
||||
.formats = OMAP_HDMI_FORMATS,
|
||||
},
|
||||
.ops = &omap_hdmi_dai_ops,
|
||||
};
|
||||
|
||||
static const struct snd_soc_component_driver omap_hdmi_component = {
|
||||
.name = DRV_NAME,
|
||||
};
|
||||
|
||||
static int omap_hdmi_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct resource *hdmi_rsrc;
|
||||
struct hdmi_priv *hdmi_data;
|
||||
bool hdmi_dev_found = false;
|
||||
|
||||
hdmi_data = devm_kzalloc(&pdev->dev, sizeof(*hdmi_data), GFP_KERNEL);
|
||||
if (hdmi_data == NULL) {
|
||||
dev_err(&pdev->dev, "Cannot allocate memory for HDMI data\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
hdmi_rsrc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!hdmi_rsrc) {
|
||||
dev_err(&pdev->dev, "Cannot obtain IORESOURCE_MEM HDMI\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
hdmi_data->dma_data.addr = hdmi_rsrc->start + OMAP_HDMI_AUDIO_DMA_PORT;
|
||||
|
||||
hdmi_rsrc = platform_get_resource(pdev, IORESOURCE_DMA, 0);
|
||||
if (!hdmi_rsrc) {
|
||||
dev_err(&pdev->dev, "Cannot obtain IORESOURCE_DMA HDMI\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
hdmi_data->dma_req = hdmi_rsrc->start;
|
||||
hdmi_data->dma_data.filter_data = &hdmi_data->dma_req;
|
||||
hdmi_data->dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
|
||||
/*
|
||||
* TODO: We assume that there is only one DSS HDMI device. Future
|
||||
* OMAP implementations may support more than one HDMI devices and
|
||||
* we should provided separate audio support for all of them.
|
||||
*/
|
||||
/* Find an HDMI device. */
|
||||
for_each_dss_dev(hdmi_data->dssdev) {
|
||||
omap_dss_get_device(hdmi_data->dssdev);
|
||||
|
||||
if (!hdmi_data->dssdev->driver) {
|
||||
omap_dss_put_device(hdmi_data->dssdev);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hdmi_data->dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
|
||||
hdmi_dev_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hdmi_dev_found) {
|
||||
dev_err(&pdev->dev, "no driver for HDMI display found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dev_set_drvdata(&pdev->dev, hdmi_data);
|
||||
ret = snd_soc_register_component(&pdev->dev, &omap_hdmi_component,
|
||||
&omap_hdmi_dai, 1);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return omap_pcm_platform_register(&pdev->dev);
|
||||
}
|
||||
|
||||
static int omap_hdmi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct hdmi_priv *hdmi_data = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
snd_soc_unregister_component(&pdev->dev);
|
||||
|
||||
if (hdmi_data == NULL) {
|
||||
dev_err(&pdev->dev, "cannot obtain HDMi data\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
omap_dss_put_device(hdmi_data->dssdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver hdmi_dai_driver = {
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = omap_hdmi_probe,
|
||||
.remove = omap_hdmi_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(hdmi_dai_driver);
|
||||
|
||||
MODULE_AUTHOR("Jorge Candelaria <jorge.candelaria@ti.com>");
|
||||
MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>");
|
||||
MODULE_DESCRIPTION("OMAP HDMI SoC Interface");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:" DRV_NAME);
|
@ -1,38 +0,0 @@
|
||||
/*
|
||||
* omap-hdmi.h
|
||||
*
|
||||
* Definitions for OMAP ALSA SoC DAI driver for HDMI audio on OMAP4 processors.
|
||||
* Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
|
||||
* Authors: Jorge Candelaria <jorge.candelaria@ti.com>
|
||||
* Ricardo Neri <ricardo.neri@ti.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __OMAP_HDMI_H__
|
||||
#define __OMAP_HDMI_H__
|
||||
|
||||
#define OMAP_HDMI_AUDIO_DMA_PORT 0x8c
|
||||
|
||||
#define OMAP_HDMI_RATES (SNDRV_PCM_RATE_32000 | \
|
||||
SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
|
||||
SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | \
|
||||
SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000)
|
||||
|
||||
#define OMAP_HDMI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
|
||||
SNDRV_PCM_FMTBIT_S24_LE)
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user