mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-18 09:44:18 +08:00
Merge branches '3.20/fbdev' and '3.20/omapdss' into for-next
Merge fbdev topic branches
This commit is contained in:
commit
d6c2152b3e
69
Documentation/devicetree/bindings/video/ti,dra7-dss.txt
Normal file
69
Documentation/devicetree/bindings/video/ti,dra7-dss.txt
Normal file
@ -0,0 +1,69 @@
|
||||
Texas Instruments DRA7x Display Subsystem
|
||||
=========================================
|
||||
|
||||
See Documentation/devicetree/bindings/video/ti,omap-dss.txt for generic
|
||||
description about OMAP Display Subsystem bindings.
|
||||
|
||||
DSS Core
|
||||
--------
|
||||
|
||||
Required properties:
|
||||
- compatible: "ti,dra7-dss"
|
||||
- reg: address and length of the register spaces for 'dss'
|
||||
- ti,hwmods: "dss_core"
|
||||
- clocks: handle to fclk
|
||||
- clock-names: "fck"
|
||||
- syscon: phandle to control module core syscon node
|
||||
|
||||
Optional properties:
|
||||
|
||||
Some DRA7xx SoCs have one dedicated video PLL, some have two. These properties
|
||||
can be used to describe the video PLLs:
|
||||
|
||||
- reg: address and length of the register spaces for 'pll1_clkctrl',
|
||||
'pll1', 'pll2_clkctrl', 'pll2'
|
||||
- clocks: handle to video1 pll clock and video2 pll clock
|
||||
- clock-names: "video1_clk" and "video2_clk"
|
||||
|
||||
Required nodes:
|
||||
- DISPC
|
||||
|
||||
Optional nodes:
|
||||
- DSS Submodules: HDMI
|
||||
- Video port for DPI output
|
||||
|
||||
DPI Endpoint required properties:
|
||||
- data-lines: number of lines used
|
||||
|
||||
|
||||
DISPC
|
||||
-----
|
||||
|
||||
Required properties:
|
||||
- compatible: "ti,dra7-dispc"
|
||||
- reg: address and length of the register space
|
||||
- ti,hwmods: "dss_dispc"
|
||||
- interrupts: the DISPC interrupt
|
||||
- clocks: handle to fclk
|
||||
- clock-names: "fck"
|
||||
|
||||
HDMI
|
||||
----
|
||||
|
||||
Required properties:
|
||||
- compatible: "ti,dra7-hdmi"
|
||||
- reg: addresses and lengths of the register spaces for 'wp', 'pll', 'phy',
|
||||
'core'
|
||||
- reg-names: "wp", "pll", "phy", "core"
|
||||
- interrupts: the HDMI interrupt line
|
||||
- ti,hwmods: "dss_hdmi"
|
||||
- vdda-supply: vdda power supply
|
||||
- clocks: handles to fclk and pll clock
|
||||
- clock-names: "fck", "sys_clk"
|
||||
|
||||
Optional nodes:
|
||||
- Video port for HDMI output
|
||||
|
||||
HDMI Endpoint optional properties:
|
||||
- lanes: list of 8 pin numbers for the HDMI lanes: CLK+, CLK-, D0+, D0-,
|
||||
D1+, D1-, D2+, D2-. (default: 0,1,2,3,4,5,6,7)
|
38
Documentation/devicetree/bindings/video/ti,opa362.txt
Normal file
38
Documentation/devicetree/bindings/video/ti,opa362.txt
Normal file
@ -0,0 +1,38 @@
|
||||
OPA362 analog video amplifier
|
||||
|
||||
Required properties:
|
||||
- compatible: "ti,opa362"
|
||||
- enable-gpios: enable/disable output gpio
|
||||
|
||||
Required node:
|
||||
- Video port 0 for opa362 input
|
||||
- Video port 1 for opa362 output
|
||||
|
||||
Example:
|
||||
|
||||
tv_amp: opa362 {
|
||||
compatible = "ti,opa362";
|
||||
enable-gpios = <&gpio1 23 0>; /* GPIO to enable video out amplifier */
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
port@0 {
|
||||
reg = <0>;
|
||||
opa_in: endpoint@0 {
|
||||
remote-endpoint = <&venc_out>;
|
||||
};
|
||||
};
|
||||
|
||||
port@1 {
|
||||
reg = <1>;
|
||||
opa_out: endpoint@0 {
|
||||
remote-endpoint = <&tv_connector_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
@ -1,6 +1,12 @@
|
||||
menu "OMAP Display Device Drivers (new device model)"
|
||||
depends on OMAP2_DSS
|
||||
|
||||
config DISPLAY_ENCODER_OPA362
|
||||
tristate "OPA362 external analog amplifier"
|
||||
help
|
||||
Driver for OPA362 external analog TV amplifier controlled
|
||||
through a GPIO.
|
||||
|
||||
config DISPLAY_ENCODER_TFP410
|
||||
tristate "TFP410 DPI to DVI Encoder"
|
||||
help
|
||||
|
@ -1,3 +1,4 @@
|
||||
obj-$(CONFIG_DISPLAY_ENCODER_OPA362) += encoder-opa362.o
|
||||
obj-$(CONFIG_DISPLAY_ENCODER_TFP410) += encoder-tfp410.o
|
||||
obj-$(CONFIG_DISPLAY_ENCODER_TPD12S015) += encoder-tpd12s015.o
|
||||
obj-$(CONFIG_DISPLAY_CONNECTOR_DVI) += connector-dvi.o
|
||||
|
@ -208,7 +208,7 @@ static int tvc_probe_pdata(struct platform_device *pdev)
|
||||
ddata->in = in;
|
||||
|
||||
ddata->connector_type = pdata->connector_type;
|
||||
ddata->invert_polarity = ddata->invert_polarity;
|
||||
ddata->invert_polarity = pdata->invert_polarity;
|
||||
|
||||
dssdev = &ddata->dssdev;
|
||||
dssdev->name = pdata->name;
|
||||
|
285
drivers/video/fbdev/omap2/displays-new/encoder-opa362.c
Normal file
285
drivers/video/fbdev/omap2/displays-new/encoder-opa362.c
Normal file
@ -0,0 +1,285 @@
|
||||
/*
|
||||
* OPA362 analog video amplifier with output/power control
|
||||
*
|
||||
* Copyright (C) 2014 Golden Delicious Computers
|
||||
* Author: H. Nikolaus Schaller <hns@goldelico.com>
|
||||
*
|
||||
* based on encoder-tfp410
|
||||
*
|
||||
* Copyright (C) 2013 Texas Instruments
|
||||
* Author: Tomi Valkeinen <tomi.valkeinen@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.
|
||||
*/
|
||||
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of_gpio.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
|
||||
struct panel_drv_data {
|
||||
struct omap_dss_device dssdev;
|
||||
struct omap_dss_device *in;
|
||||
|
||||
struct gpio_desc *enable_gpio;
|
||||
|
||||
struct omap_video_timings timings;
|
||||
};
|
||||
|
||||
#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
|
||||
|
||||
static int opa362_connect(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
int r;
|
||||
|
||||
dev_dbg(dssdev->dev, "connect\n");
|
||||
|
||||
if (omapdss_device_is_connected(dssdev))
|
||||
return -EBUSY;
|
||||
|
||||
r = in->ops.atv->connect(in, dssdev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dst->src = dssdev;
|
||||
dssdev->dst = dst;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void opa362_disconnect(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
dev_dbg(dssdev->dev, "disconnect\n");
|
||||
|
||||
WARN_ON(!omapdss_device_is_connected(dssdev));
|
||||
if (!omapdss_device_is_connected(dssdev))
|
||||
return;
|
||||
|
||||
WARN_ON(dst != dssdev->dst);
|
||||
if (dst != dssdev->dst)
|
||||
return;
|
||||
|
||||
dst->src = NULL;
|
||||
dssdev->dst = NULL;
|
||||
|
||||
in->ops.atv->disconnect(in, &ddata->dssdev);
|
||||
}
|
||||
|
||||
static int opa362_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
int r;
|
||||
|
||||
dev_dbg(dssdev->dev, "enable\n");
|
||||
|
||||
if (!omapdss_device_is_connected(dssdev))
|
||||
return -ENODEV;
|
||||
|
||||
if (omapdss_device_is_enabled(dssdev))
|
||||
return 0;
|
||||
|
||||
in->ops.atv->set_timings(in, &ddata->timings);
|
||||
|
||||
r = in->ops.atv->enable(in);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (ddata->enable_gpio)
|
||||
gpiod_set_value_cansleep(ddata->enable_gpio, 1);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void opa362_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
dev_dbg(dssdev->dev, "disable\n");
|
||||
|
||||
if (!omapdss_device_is_enabled(dssdev))
|
||||
return;
|
||||
|
||||
if (ddata->enable_gpio)
|
||||
gpiod_set_value_cansleep(ddata->enable_gpio, 0);
|
||||
|
||||
in->ops.atv->disable(in);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
|
||||
}
|
||||
|
||||
static void opa362_set_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
dev_dbg(dssdev->dev, "set_timings\n");
|
||||
|
||||
ddata->timings = *timings;
|
||||
dssdev->panel.timings = *timings;
|
||||
|
||||
in->ops.atv->set_timings(in, timings);
|
||||
}
|
||||
|
||||
static void opa362_get_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
|
||||
dev_dbg(dssdev->dev, "get_timings\n");
|
||||
|
||||
*timings = ddata->timings;
|
||||
}
|
||||
|
||||
static int opa362_check_timings(struct omap_dss_device *dssdev,
|
||||
struct omap_video_timings *timings)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
dev_dbg(dssdev->dev, "check_timings\n");
|
||||
|
||||
return in->ops.atv->check_timings(in, timings);
|
||||
}
|
||||
|
||||
static void opa362_set_type(struct omap_dss_device *dssdev,
|
||||
enum omap_dss_venc_type type)
|
||||
{
|
||||
/* we can only drive a COMPOSITE output */
|
||||
WARN_ON(type != OMAP_DSS_VENC_TYPE_COMPOSITE);
|
||||
|
||||
}
|
||||
|
||||
static const struct omapdss_atv_ops opa362_atv_ops = {
|
||||
.connect = opa362_connect,
|
||||
.disconnect = opa362_disconnect,
|
||||
|
||||
.enable = opa362_enable,
|
||||
.disable = opa362_disable,
|
||||
|
||||
.check_timings = opa362_check_timings,
|
||||
.set_timings = opa362_set_timings,
|
||||
.get_timings = opa362_get_timings,
|
||||
|
||||
.set_type = opa362_set_type,
|
||||
};
|
||||
|
||||
static int opa362_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
struct panel_drv_data *ddata;
|
||||
struct omap_dss_device *dssdev, *in;
|
||||
struct gpio_desc *gpio;
|
||||
int r;
|
||||
|
||||
dev_dbg(&pdev->dev, "probe\n");
|
||||
|
||||
if (node == NULL) {
|
||||
dev_err(&pdev->dev, "Unable to find device tree\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
|
||||
if (!ddata)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, ddata);
|
||||
|
||||
gpio = devm_gpiod_get(&pdev->dev, "enable");
|
||||
if (IS_ERR(gpio)) {
|
||||
if (PTR_ERR(gpio) != -ENOENT)
|
||||
return PTR_ERR(gpio);
|
||||
|
||||
gpio = NULL;
|
||||
} else {
|
||||
gpiod_direction_output(gpio, 0);
|
||||
}
|
||||
|
||||
ddata->enable_gpio = gpio;
|
||||
|
||||
in = omapdss_of_find_source_for_first_ep(node);
|
||||
if (IS_ERR(in)) {
|
||||
dev_err(&pdev->dev, "failed to find video source\n");
|
||||
return PTR_ERR(in);
|
||||
}
|
||||
|
||||
ddata->in = in;
|
||||
|
||||
dssdev = &ddata->dssdev;
|
||||
dssdev->ops.atv = &opa362_atv_ops;
|
||||
dssdev->dev = &pdev->dev;
|
||||
dssdev->type = OMAP_DISPLAY_TYPE_VENC;
|
||||
dssdev->output_type = OMAP_DISPLAY_TYPE_VENC;
|
||||
dssdev->owner = THIS_MODULE;
|
||||
|
||||
r = omapdss_register_output(dssdev);
|
||||
if (r) {
|
||||
dev_err(&pdev->dev, "Failed to register output\n");
|
||||
goto err_reg;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err_reg:
|
||||
omap_dss_put_device(ddata->in);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int __exit opa362_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
|
||||
struct omap_dss_device *dssdev = &ddata->dssdev;
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
|
||||
omapdss_unregister_output(&ddata->dssdev);
|
||||
|
||||
WARN_ON(omapdss_device_is_enabled(dssdev));
|
||||
if (omapdss_device_is_enabled(dssdev))
|
||||
opa362_disable(dssdev);
|
||||
|
||||
WARN_ON(omapdss_device_is_connected(dssdev));
|
||||
if (omapdss_device_is_connected(dssdev))
|
||||
opa362_disconnect(dssdev, dssdev->dst);
|
||||
|
||||
omap_dss_put_device(in);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id opa362_of_match[] = {
|
||||
{ .compatible = "omapdss,ti,opa362", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, opa362_of_match);
|
||||
|
||||
static struct platform_driver opa362_driver = {
|
||||
.probe = opa362_probe,
|
||||
.remove = __exit_p(opa362_remove),
|
||||
.driver = {
|
||||
.name = "amplifier-opa362",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = opa362_of_match,
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(opa362_driver);
|
||||
|
||||
MODULE_AUTHOR("H. Nikolaus Schaller <hns@goldelico.com>");
|
||||
MODULE_DESCRIPTION("OPA362 analog video amplifier with output/power control");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -29,33 +29,10 @@ struct panel_drv_data {
|
||||
int hpd_gpio;
|
||||
|
||||
struct omap_video_timings timings;
|
||||
|
||||
struct completion hpd_completion;
|
||||
};
|
||||
|
||||
#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
|
||||
|
||||
static irqreturn_t tpd_hpd_irq_handler(int irq, void *data)
|
||||
{
|
||||
struct panel_drv_data *ddata = data;
|
||||
bool hpd;
|
||||
|
||||
hpd = gpio_get_value_cansleep(ddata->hpd_gpio);
|
||||
|
||||
dev_dbg(ddata->dssdev.dev, "hpd %d\n", hpd);
|
||||
|
||||
if (gpio_is_valid(ddata->ls_oe_gpio)) {
|
||||
if (hpd)
|
||||
gpio_set_value_cansleep(ddata->ls_oe_gpio, 1);
|
||||
else
|
||||
gpio_set_value_cansleep(ddata->ls_oe_gpio, 0);
|
||||
}
|
||||
|
||||
complete_all(&ddata->hpd_completion);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int tpd_connect(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
@ -70,23 +47,10 @@ static int tpd_connect(struct omap_dss_device *dssdev,
|
||||
dst->src = dssdev;
|
||||
dssdev->dst = dst;
|
||||
|
||||
reinit_completion(&ddata->hpd_completion);
|
||||
|
||||
gpio_set_value_cansleep(ddata->ct_cp_hpd_gpio, 1);
|
||||
/* DC-DC converter needs at max 300us to get to 90% of 5V */
|
||||
udelay(300);
|
||||
|
||||
/*
|
||||
* If there's a cable connected, wait for the hpd irq to trigger,
|
||||
* which turns on the level shifters.
|
||||
*/
|
||||
if (gpio_get_value_cansleep(ddata->hpd_gpio)) {
|
||||
unsigned long to;
|
||||
to = wait_for_completion_timeout(&ddata->hpd_completion,
|
||||
msecs_to_jiffies(250));
|
||||
WARN_ON_ONCE(to == 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -179,11 +143,20 @@ static int tpd_read_edid(struct omap_dss_device *dssdev,
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *in = ddata->in;
|
||||
int r;
|
||||
|
||||
if (!gpio_get_value_cansleep(ddata->hpd_gpio))
|
||||
return -ENODEV;
|
||||
|
||||
return in->ops.hdmi->read_edid(in, edid, len);
|
||||
if (gpio_is_valid(ddata->ls_oe_gpio))
|
||||
gpio_set_value_cansleep(ddata->ls_oe_gpio, 1);
|
||||
|
||||
r = in->ops.hdmi->read_edid(in, edid, len);
|
||||
|
||||
if (gpio_is_valid(ddata->ls_oe_gpio))
|
||||
gpio_set_value_cansleep(ddata->ls_oe_gpio, 0);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static bool tpd_detect(struct omap_dss_device *dssdev)
|
||||
@ -309,8 +282,6 @@ static int tpd_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, ddata);
|
||||
|
||||
init_completion(&ddata->hpd_completion);
|
||||
|
||||
if (dev_get_platdata(&pdev->dev)) {
|
||||
r = tpd_probe_pdata(pdev);
|
||||
if (r)
|
||||
@ -340,13 +311,6 @@ static int tpd_probe(struct platform_device *pdev)
|
||||
if (r)
|
||||
goto err_gpio;
|
||||
|
||||
r = devm_request_threaded_irq(&pdev->dev, gpio_to_irq(ddata->hpd_gpio),
|
||||
NULL, tpd_hpd_irq_handler,
|
||||
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
|
||||
IRQF_ONESHOT, "hpd", ddata);
|
||||
if (r)
|
||||
goto err_irq;
|
||||
|
||||
dssdev = &ddata->dssdev;
|
||||
dssdev->ops.hdmi = &tpd_hdmi_ops;
|
||||
dssdev->dev = &pdev->dev;
|
||||
@ -365,7 +329,6 @@ static int tpd_probe(struct platform_device *pdev)
|
||||
|
||||
return 0;
|
||||
err_reg:
|
||||
err_irq:
|
||||
err_gpio:
|
||||
omap_dss_put_device(ddata->in);
|
||||
return r;
|
||||
|
@ -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 pll.o
|
||||
output.o dss-of.o pll.o video-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
|
||||
|
@ -36,6 +36,9 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
|
||||
@ -117,6 +120,9 @@ static struct {
|
||||
const struct dispc_features *feat;
|
||||
|
||||
bool is_enabled;
|
||||
|
||||
struct regmap *syscon_pol;
|
||||
u32 syscon_pol_offset;
|
||||
} dispc;
|
||||
|
||||
enum omap_color_component {
|
||||
@ -2958,6 +2964,25 @@ static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw,
|
||||
FLD_VAL(vsync_level, 12, 12);
|
||||
|
||||
dispc_write_reg(DISPC_POL_FREQ(channel), l);
|
||||
|
||||
if (dispc.syscon_pol) {
|
||||
const int shifts[] = {
|
||||
[OMAP_DSS_CHANNEL_LCD] = 0,
|
||||
[OMAP_DSS_CHANNEL_LCD2] = 1,
|
||||
[OMAP_DSS_CHANNEL_LCD3] = 2,
|
||||
};
|
||||
|
||||
u32 mask, val;
|
||||
|
||||
mask = (1 << 0) | (1 << 3) | (1 << 6);
|
||||
val = (rf << 0) | (ipc << 3) | (onoff << 6);
|
||||
|
||||
mask <<= 16 + shifts[channel];
|
||||
val <<= 16 + shifts[channel];
|
||||
|
||||
regmap_update_bits(dispc.syscon_pol, dispc.syscon_pol_offset,
|
||||
mask, val);
|
||||
}
|
||||
}
|
||||
|
||||
/* change name to mode? */
|
||||
@ -3037,10 +3062,16 @@ unsigned long dispc_fclk_rate(void)
|
||||
break;
|
||||
case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
|
||||
pll = dss_pll_find("dsi0");
|
||||
if (!pll)
|
||||
pll = dss_pll_find("video0");
|
||||
|
||||
r = pll->cinfo.clkout[0];
|
||||
break;
|
||||
case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
|
||||
pll = dss_pll_find("dsi1");
|
||||
if (!pll)
|
||||
pll = dss_pll_find("video1");
|
||||
|
||||
r = pll->cinfo.clkout[0];
|
||||
break;
|
||||
default:
|
||||
@ -3069,10 +3100,16 @@ unsigned long dispc_mgr_lclk_rate(enum omap_channel channel)
|
||||
break;
|
||||
case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
|
||||
pll = dss_pll_find("dsi0");
|
||||
if (!pll)
|
||||
pll = dss_pll_find("video0");
|
||||
|
||||
r = pll->cinfo.clkout[0];
|
||||
break;
|
||||
case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
|
||||
pll = dss_pll_find("dsi1");
|
||||
if (!pll)
|
||||
pll = dss_pll_find("video1");
|
||||
|
||||
r = pll->cinfo.clkout[0];
|
||||
break;
|
||||
default:
|
||||
@ -3668,6 +3705,7 @@ static int __init dispc_init_features(struct platform_device *pdev)
|
||||
break;
|
||||
|
||||
case OMAPDSS_VER_OMAP5:
|
||||
case OMAPDSS_VER_DRA7xx:
|
||||
src = &omap54xx_dispc_feats;
|
||||
break;
|
||||
|
||||
@ -3728,6 +3766,7 @@ static int __init omap_dispchw_probe(struct platform_device *pdev)
|
||||
u32 rev;
|
||||
int r = 0;
|
||||
struct resource *dispc_mem;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
|
||||
dispc.pdev = pdev;
|
||||
|
||||
@ -3754,6 +3793,20 @@ static int __init omap_dispchw_probe(struct platform_device *pdev)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (np && of_property_read_bool(np, "syscon-pol")) {
|
||||
dispc.syscon_pol = syscon_regmap_lookup_by_phandle(np, "syscon-pol");
|
||||
if (IS_ERR(dispc.syscon_pol)) {
|
||||
dev_err(&pdev->dev, "failed to get syscon-pol regmap\n");
|
||||
return PTR_ERR(dispc.syscon_pol);
|
||||
}
|
||||
|
||||
if (of_property_read_u32_index(np, "syscon-pol", 1,
|
||||
&dispc.syscon_pol_offset)) {
|
||||
dev_err(&pdev->dev, "failed to get syscon-pol offset\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
r = dispc_runtime_get();
|
||||
@ -3832,6 +3885,7 @@ static const struct of_device_id dispc_of_match[] = {
|
||||
{ .compatible = "ti,omap3-dispc", },
|
||||
{ .compatible = "ti,omap4-dispc", },
|
||||
{ .compatible = "ti,omap5-dispc", },
|
||||
{ .compatible = "ti,dra7-dispc", },
|
||||
{},
|
||||
};
|
||||
|
||||
|
@ -106,6 +106,17 @@ static struct dss_pll *dpi_get_pll(enum omap_channel channel)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
case OMAPDSS_VER_DRA7xx:
|
||||
switch (channel) {
|
||||
case OMAP_DSS_CHANNEL_LCD:
|
||||
case OMAP_DSS_CHANNEL_LCD2:
|
||||
return dss_pll_find("video0");
|
||||
case OMAP_DSS_CHANNEL_LCD3:
|
||||
return dss_pll_find("video1");
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
@ -590,6 +601,10 @@ static void dpi_init_pll(struct dpi_data *dpi)
|
||||
if (!pll)
|
||||
return;
|
||||
|
||||
/* On DRA7 we need to set a mux to use the PLL */
|
||||
if (omapdss_get_version() == OMAPDSS_VER_DRA7xx)
|
||||
dss_ctrl_pll_set_control_mux(pll->id, dpi->output.dispc_channel);
|
||||
|
||||
if (dpi_verify_dsi_pll(pll)) {
|
||||
DSSWARN("DSI PLL not operational\n");
|
||||
return;
|
||||
@ -615,6 +630,17 @@ static enum omap_channel dpi_get_channel(int port_num)
|
||||
case OMAPDSS_VER_AM43xx:
|
||||
return OMAP_DSS_CHANNEL_LCD;
|
||||
|
||||
case OMAPDSS_VER_DRA7xx:
|
||||
switch (port_num) {
|
||||
case 2:
|
||||
return OMAP_DSS_CHANNEL_LCD3;
|
||||
case 1:
|
||||
return OMAP_DSS_CHANNEL_LCD2;
|
||||
case 0:
|
||||
default:
|
||||
return OMAP_DSS_CHANNEL_LCD;
|
||||
}
|
||||
|
||||
case OMAPDSS_VER_OMAP4430_ES1:
|
||||
case OMAPDSS_VER_OMAP4430_ES2:
|
||||
case OMAPDSS_VER_OMAP4:
|
||||
|
@ -5238,6 +5238,7 @@ static int dsi_init_pll_data(struct platform_device *dsidev)
|
||||
}
|
||||
|
||||
pll->name = dsi->module_id == 0 ? "dsi0" : "dsi1";
|
||||
pll->id = dsi->module_id == 0 ? DSS_PLL_DSI1 : DSS_PLL_DSI2;
|
||||
pll->clkin = clk;
|
||||
pll->base = dsi->pll_base;
|
||||
|
||||
|
@ -34,7 +34,10 @@
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
|
||||
@ -63,14 +66,11 @@ struct dss_reg {
|
||||
#define REG_FLD_MOD(idx, val, start, end) \
|
||||
dss_write_reg(idx, FLD_MOD(dss_read_reg(idx), val, start, end))
|
||||
|
||||
static int dss_runtime_get(void);
|
||||
static void dss_runtime_put(void);
|
||||
|
||||
struct dss_features {
|
||||
u8 fck_div_max;
|
||||
u8 dss_fck_multiplier;
|
||||
const char *parent_clk_name;
|
||||
enum omap_display_type *ports;
|
||||
const enum omap_display_type *ports;
|
||||
int num_ports;
|
||||
int (*dpi_select_source)(int port, enum omap_channel channel);
|
||||
};
|
||||
@ -78,6 +78,8 @@ struct dss_features {
|
||||
static struct {
|
||||
struct platform_device *pdev;
|
||||
void __iomem *base;
|
||||
struct regmap *syscon_pll_ctrl;
|
||||
u32 syscon_pll_ctrl_offset;
|
||||
|
||||
struct clk *parent_clk;
|
||||
struct clk *dss_clk;
|
||||
@ -95,6 +97,9 @@ static struct {
|
||||
u32 ctx[DSS_SZ_REGS / sizeof(u32)];
|
||||
|
||||
const struct dss_features *feat;
|
||||
|
||||
struct dss_pll *video1_pll;
|
||||
struct dss_pll *video2_pll;
|
||||
} dss;
|
||||
|
||||
static const char * const dss_generic_clk_source_names[] = {
|
||||
@ -158,6 +163,99 @@ static void dss_restore_context(void)
|
||||
#undef SR
|
||||
#undef RR
|
||||
|
||||
void dss_ctrl_pll_enable(enum dss_pll_id pll_id, bool enable)
|
||||
{
|
||||
unsigned shift;
|
||||
unsigned val;
|
||||
|
||||
if (!dss.syscon_pll_ctrl)
|
||||
return;
|
||||
|
||||
val = !enable;
|
||||
|
||||
switch (pll_id) {
|
||||
case DSS_PLL_VIDEO1:
|
||||
shift = 0;
|
||||
break;
|
||||
case DSS_PLL_VIDEO2:
|
||||
shift = 1;
|
||||
break;
|
||||
case DSS_PLL_HDMI:
|
||||
shift = 2;
|
||||
break;
|
||||
default:
|
||||
DSSERR("illegal DSS PLL ID %d\n", pll_id);
|
||||
return;
|
||||
}
|
||||
|
||||
regmap_update_bits(dss.syscon_pll_ctrl, dss.syscon_pll_ctrl_offset,
|
||||
1 << shift, val << shift);
|
||||
}
|
||||
|
||||
void dss_ctrl_pll_set_control_mux(enum dss_pll_id pll_id,
|
||||
enum omap_channel channel)
|
||||
{
|
||||
unsigned shift, val;
|
||||
|
||||
if (!dss.syscon_pll_ctrl)
|
||||
return;
|
||||
|
||||
switch (channel) {
|
||||
case OMAP_DSS_CHANNEL_LCD:
|
||||
shift = 3;
|
||||
|
||||
switch (pll_id) {
|
||||
case DSS_PLL_VIDEO1:
|
||||
val = 0; break;
|
||||
case DSS_PLL_HDMI:
|
||||
val = 1; break;
|
||||
default:
|
||||
DSSERR("error in PLL mux config for LCD\n");
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
case OMAP_DSS_CHANNEL_LCD2:
|
||||
shift = 5;
|
||||
|
||||
switch (pll_id) {
|
||||
case DSS_PLL_VIDEO1:
|
||||
val = 0; break;
|
||||
case DSS_PLL_VIDEO2:
|
||||
val = 1; break;
|
||||
case DSS_PLL_HDMI:
|
||||
val = 2; break;
|
||||
default:
|
||||
DSSERR("error in PLL mux config for LCD2\n");
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
case OMAP_DSS_CHANNEL_LCD3:
|
||||
shift = 7;
|
||||
|
||||
switch (pll_id) {
|
||||
case DSS_PLL_VIDEO1:
|
||||
val = 1; break;
|
||||
case DSS_PLL_VIDEO2:
|
||||
val = 0; break;
|
||||
case DSS_PLL_HDMI:
|
||||
val = 2; break;
|
||||
default:
|
||||
DSSERR("error in PLL mux config for LCD3\n");
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
DSSERR("error in PLL mux config\n");
|
||||
return;
|
||||
}
|
||||
|
||||
regmap_update_bits(dss.syscon_pll_ctrl, dss.syscon_pll_ctrl_offset,
|
||||
0x3 << shift, val << shift);
|
||||
}
|
||||
|
||||
void dss_sdi_init(int datapairs)
|
||||
{
|
||||
u32 l;
|
||||
@ -605,6 +703,26 @@ static int dss_dpi_select_source_omap5(int port, enum omap_channel channel)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dss_dpi_select_source_dra7xx(int port, enum omap_channel channel)
|
||||
{
|
||||
switch (port) {
|
||||
case 0:
|
||||
return dss_dpi_select_source_omap5(port, channel);
|
||||
case 1:
|
||||
if (channel != OMAP_DSS_CHANNEL_LCD2)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case 2:
|
||||
if (channel != OMAP_DSS_CHANNEL_LCD3)
|
||||
return -EINVAL;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dss_dpi_select_source(int port, enum omap_channel channel)
|
||||
{
|
||||
return dss.feat->dpi_select_source(port, channel);
|
||||
@ -643,7 +761,7 @@ static void dss_put_clocks(void)
|
||||
clk_put(dss.parent_clk);
|
||||
}
|
||||
|
||||
static int dss_runtime_get(void)
|
||||
int dss_runtime_get(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
@ -654,7 +772,7 @@ static int dss_runtime_get(void)
|
||||
return r < 0 ? r : 0;
|
||||
}
|
||||
|
||||
static void dss_runtime_put(void)
|
||||
void dss_runtime_put(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
@ -677,15 +795,21 @@ void dss_debug_dump_clocks(struct seq_file *s)
|
||||
#endif
|
||||
|
||||
|
||||
static enum omap_display_type omap2plus_ports[] = {
|
||||
static const enum omap_display_type omap2plus_ports[] = {
|
||||
OMAP_DISPLAY_TYPE_DPI,
|
||||
};
|
||||
|
||||
static enum omap_display_type omap34xx_ports[] = {
|
||||
static const enum omap_display_type omap34xx_ports[] = {
|
||||
OMAP_DISPLAY_TYPE_DPI,
|
||||
OMAP_DISPLAY_TYPE_SDI,
|
||||
};
|
||||
|
||||
static const enum omap_display_type dra7xx_ports[] = {
|
||||
OMAP_DISPLAY_TYPE_DPI,
|
||||
OMAP_DISPLAY_TYPE_DPI,
|
||||
OMAP_DISPLAY_TYPE_DPI,
|
||||
};
|
||||
|
||||
static const struct dss_features omap24xx_dss_feats __initconst = {
|
||||
/*
|
||||
* fck div max is really 16, but the divider range has gaps. The range
|
||||
@ -744,6 +868,15 @@ static const struct dss_features am43xx_dss_feats __initconst = {
|
||||
.num_ports = ARRAY_SIZE(omap2plus_ports),
|
||||
};
|
||||
|
||||
static const struct dss_features dra7xx_dss_feats __initconst = {
|
||||
.fck_div_max = 64,
|
||||
.dss_fck_multiplier = 1,
|
||||
.parent_clk_name = "dpll_per_x2_ck",
|
||||
.dpi_select_source = &dss_dpi_select_source_dra7xx,
|
||||
.ports = dra7xx_ports,
|
||||
.num_ports = ARRAY_SIZE(dra7xx_ports),
|
||||
};
|
||||
|
||||
static int __init dss_init_features(struct platform_device *pdev)
|
||||
{
|
||||
const struct dss_features *src;
|
||||
@ -784,6 +917,10 @@ static int __init dss_init_features(struct platform_device *pdev)
|
||||
src = &am43xx_dss_feats;
|
||||
break;
|
||||
|
||||
case OMAPDSS_VER_DRA7xx:
|
||||
src = &dra7xx_dss_feats;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -ENODEV;
|
||||
}
|
||||
@ -884,8 +1021,10 @@ static void __exit dss_uninit_ports(struct platform_device *pdev)
|
||||
static int __init omap_dsshw_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *dss_mem;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
u32 rev;
|
||||
int r;
|
||||
struct regulator *pll_regulator;
|
||||
|
||||
dss.pdev = pdev;
|
||||
|
||||
@ -940,6 +1079,57 @@ static int __init omap_dsshw_probe(struct platform_device *pdev)
|
||||
|
||||
dss_init_ports(pdev);
|
||||
|
||||
if (np && of_property_read_bool(np, "syscon-pll-ctrl")) {
|
||||
dss.syscon_pll_ctrl = syscon_regmap_lookup_by_phandle(np,
|
||||
"syscon-pll-ctrl");
|
||||
if (IS_ERR(dss.syscon_pll_ctrl)) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to get syscon-pll-ctrl regmap\n");
|
||||
return PTR_ERR(dss.syscon_pll_ctrl);
|
||||
}
|
||||
|
||||
if (of_property_read_u32_index(np, "syscon-pll-ctrl", 1,
|
||||
&dss.syscon_pll_ctrl_offset)) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to get syscon-pll-ctrl offset\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
pll_regulator = devm_regulator_get(&pdev->dev, "vdda_video");
|
||||
if (IS_ERR(pll_regulator)) {
|
||||
r = PTR_ERR(pll_regulator);
|
||||
|
||||
switch (r) {
|
||||
case -ENOENT:
|
||||
pll_regulator = NULL;
|
||||
break;
|
||||
|
||||
case -EPROBE_DEFER:
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
default:
|
||||
DSSERR("can't get DPLL VDDA regulator\n");
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
if (of_property_match_string(np, "reg-names", "pll1") >= 0) {
|
||||
dss.video1_pll = dss_video_pll_init(pdev, 0, pll_regulator);
|
||||
if (IS_ERR(dss.video1_pll)) {
|
||||
r = PTR_ERR(dss.video1_pll);
|
||||
goto err_pll_init;
|
||||
}
|
||||
}
|
||||
|
||||
if (of_property_match_string(np, "reg-names", "pll2") >= 0) {
|
||||
dss.video2_pll = dss_video_pll_init(pdev, 1, pll_regulator);
|
||||
if (IS_ERR(dss.video2_pll)) {
|
||||
r = PTR_ERR(dss.video2_pll);
|
||||
goto err_pll_init;
|
||||
}
|
||||
}
|
||||
|
||||
rev = dss_read_reg(DSS_REVISION);
|
||||
printk(KERN_INFO "OMAP DSS rev %d.%d\n",
|
||||
FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
|
||||
@ -950,6 +1140,12 @@ static int __init omap_dsshw_probe(struct platform_device *pdev)
|
||||
|
||||
return 0;
|
||||
|
||||
err_pll_init:
|
||||
if (dss.video1_pll)
|
||||
dss_video_pll_uninit(dss.video1_pll);
|
||||
|
||||
if (dss.video2_pll)
|
||||
dss_video_pll_uninit(dss.video2_pll);
|
||||
err_runtime_get:
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
err_setup_clocks:
|
||||
@ -959,6 +1155,12 @@ err_setup_clocks:
|
||||
|
||||
static int __exit omap_dsshw_remove(struct platform_device *pdev)
|
||||
{
|
||||
if (dss.video1_pll)
|
||||
dss_video_pll_uninit(dss.video1_pll);
|
||||
|
||||
if (dss.video2_pll)
|
||||
dss_video_pll_uninit(dss.video2_pll);
|
||||
|
||||
dss_uninit_ports(pdev);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
@ -1003,6 +1205,7 @@ static const struct of_device_id dss_of_match[] = {
|
||||
{ .compatible = "ti,omap3-dss", },
|
||||
{ .compatible = "ti,omap4-dss", },
|
||||
{ .compatible = "ti,omap5-dss", },
|
||||
{ .compatible = "ti,dra7-dss", },
|
||||
{},
|
||||
};
|
||||
|
||||
|
@ -100,6 +100,14 @@ enum dss_writeback_channel {
|
||||
DSS_WB_LCD3_MGR = 7,
|
||||
};
|
||||
|
||||
enum dss_pll_id {
|
||||
DSS_PLL_DSI1,
|
||||
DSS_PLL_DSI2,
|
||||
DSS_PLL_HDMI,
|
||||
DSS_PLL_VIDEO1,
|
||||
DSS_PLL_VIDEO2,
|
||||
};
|
||||
|
||||
struct dss_pll;
|
||||
|
||||
#define DSS_PLL_MAX_HSDIVS 4
|
||||
@ -150,6 +158,7 @@ struct dss_pll_hw {
|
||||
|
||||
struct dss_pll {
|
||||
const char *name;
|
||||
enum dss_pll_id id;
|
||||
|
||||
struct clk *clkin;
|
||||
struct regulator *regulator;
|
||||
@ -250,6 +259,9 @@ void dss_overlay_kobj_uninit(struct omap_overlay *ovl);
|
||||
int dss_init_platform_driver(void) __init;
|
||||
void dss_uninit_platform_driver(void);
|
||||
|
||||
int dss_runtime_get(void);
|
||||
void dss_runtime_put(void);
|
||||
|
||||
unsigned long dss_get_dispc_clk_rate(void);
|
||||
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);
|
||||
@ -257,6 +269,11 @@ 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 VIDEO PLL */
|
||||
struct dss_pll *dss_video_pll_init(struct platform_device *pdev, int id,
|
||||
struct regulator *regulator);
|
||||
void dss_video_pll_uninit(struct dss_pll *pll);
|
||||
|
||||
/* 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);
|
||||
@ -265,6 +282,10 @@ u32 dss_of_port_get_port_number(struct device_node *port);
|
||||
void dss_debug_dump_clocks(struct seq_file *s);
|
||||
#endif
|
||||
|
||||
void dss_ctrl_pll_enable(enum dss_pll_id pll_id, bool enable);
|
||||
void dss_ctrl_pll_set_control_mux(enum dss_pll_id pll_id,
|
||||
enum omap_channel channel);
|
||||
|
||||
void dss_sdi_init(int datapairs);
|
||||
int dss_sdi_enable(void);
|
||||
void dss_sdi_disable(void);
|
||||
@ -446,5 +467,6 @@ 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);
|
||||
int dss_pll_wait_reset_done(struct dss_pll *pll);
|
||||
|
||||
#endif
|
||||
|
@ -223,7 +223,7 @@ static const enum omap_dss_output_id omap5_dss_supported_outputs[] = {
|
||||
OMAP_DSS_OUTPUT_DSI1 | OMAP_DSS_OUTPUT_DSI2,
|
||||
|
||||
/* OMAP_DSS_CHANNEL_DIGIT */
|
||||
OMAP_DSS_OUTPUT_HDMI | OMAP_DSS_OUTPUT_DPI,
|
||||
OMAP_DSS_OUTPUT_HDMI,
|
||||
|
||||
/* OMAP_DSS_CHANNEL_LCD2 */
|
||||
OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
|
||||
@ -943,6 +943,7 @@ void dss_features_init(enum omapdss_version version)
|
||||
break;
|
||||
|
||||
case OMAPDSS_VER_OMAP5:
|
||||
case OMAPDSS_VER_DRA7xx:
|
||||
omap_current_dss_features = &omap5_dss_features;
|
||||
break;
|
||||
|
||||
|
@ -787,6 +787,7 @@ static const struct dev_pm_ops hdmi_pm_ops = {
|
||||
|
||||
static const struct of_device_id hdmi_of_match[] = {
|
||||
{ .compatible = "ti,omap5-hdmi", },
|
||||
{ .compatible = "ti,dra7-hdmi", },
|
||||
{},
|
||||
};
|
||||
|
||||
|
@ -208,6 +208,7 @@ static int hdmi_phy_init_features(struct platform_device *pdev)
|
||||
break;
|
||||
|
||||
case OMAPDSS_VER_OMAP5:
|
||||
case OMAPDSS_VER_DRA7xx:
|
||||
src = &omap54xx_phy_feats;
|
||||
break;
|
||||
|
||||
|
@ -104,6 +104,8 @@ static int hdmi_pll_enable(struct dss_pll *dsspll)
|
||||
struct hdmi_wp_data *wp = pll->wp;
|
||||
u16 r = 0;
|
||||
|
||||
dss_ctrl_pll_enable(DSS_PLL_HDMI, true);
|
||||
|
||||
r = hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_BOTHON_ALLCLKS);
|
||||
if (r)
|
||||
return r;
|
||||
@ -117,6 +119,8 @@ static void hdmi_pll_disable(struct dss_pll *dsspll)
|
||||
struct hdmi_wp_data *wp = pll->wp;
|
||||
|
||||
hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF);
|
||||
|
||||
dss_ctrl_pll_enable(DSS_PLL_HDMI, false);
|
||||
}
|
||||
|
||||
static const struct dss_pll_ops dsi_pll_ops = {
|
||||
@ -185,6 +189,7 @@ static int dsi_init_pll_data(struct platform_device *pdev, struct hdmi_pll_data
|
||||
}
|
||||
|
||||
pll->name = "hdmi";
|
||||
pll->id = DSS_PLL_HDMI;
|
||||
pll->base = hpll->base;
|
||||
pll->clkin = clk;
|
||||
|
||||
@ -196,6 +201,7 @@ static int dsi_init_pll_data(struct platform_device *pdev, struct hdmi_pll_data
|
||||
break;
|
||||
|
||||
case OMAPDSS_VER_OMAP5:
|
||||
case OMAPDSS_VER_DRA7xx:
|
||||
pll->hw = &dss_omap5_hdmi_pll_hw;
|
||||
break;
|
||||
|
||||
|
@ -186,6 +186,7 @@ static const struct of_device_id omapdss_of_match[] __initconst = {
|
||||
{ .compatible = "ti,omap3-dss", },
|
||||
{ .compatible = "ti,omap4-dss", },
|
||||
{ .compatible = "ti,omap5-dss", },
|
||||
{ .compatible = "ti,dra7-dss", },
|
||||
{},
|
||||
};
|
||||
|
||||
|
@ -222,6 +222,16 @@ static int wait_for_bit_change(void __iomem *reg, int bitnum, int value)
|
||||
return !value;
|
||||
}
|
||||
|
||||
int dss_pll_wait_reset_done(struct dss_pll *pll)
|
||||
{
|
||||
void __iomem *base = pll->base;
|
||||
|
||||
if (wait_for_bit_change(base + PLL_STATUS, 0, 1) != 1)
|
||||
return -ETIMEDOUT;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dss_wait_hsdiv_ack(struct dss_pll *pll, u32 hsdiv_ack_mask)
|
||||
{
|
||||
int t = 100;
|
||||
|
211
drivers/video/fbdev/omap2/dss/video-pll.c
Normal file
211
drivers/video/fbdev/omap2/dss/video-pll.c
Normal file
@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Texas Instruments Ltd
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include <video/omapdss.h>
|
||||
|
||||
#include "dss.h"
|
||||
#include "dss_features.h"
|
||||
|
||||
struct dss_video_pll {
|
||||
struct dss_pll pll;
|
||||
|
||||
struct device *dev;
|
||||
|
||||
void __iomem *clkctrl_base;
|
||||
};
|
||||
|
||||
#define REG_MOD(reg, val, start, end) \
|
||||
writel_relaxed(FLD_MOD(readl_relaxed(reg), val, start, end), reg)
|
||||
|
||||
static void dss_dpll_enable_scp_clk(struct dss_video_pll *vpll)
|
||||
{
|
||||
REG_MOD(vpll->clkctrl_base, 1, 14, 14); /* CIO_CLK_ICG */
|
||||
}
|
||||
|
||||
static void dss_dpll_disable_scp_clk(struct dss_video_pll *vpll)
|
||||
{
|
||||
REG_MOD(vpll->clkctrl_base, 0, 14, 14); /* CIO_CLK_ICG */
|
||||
}
|
||||
|
||||
static void dss_dpll_power_enable(struct dss_video_pll *vpll)
|
||||
{
|
||||
REG_MOD(vpll->clkctrl_base, 2, 31, 30); /* PLL_POWER_ON_ALL */
|
||||
|
||||
/*
|
||||
* DRA7x PLL CTRL's PLL_PWR_STATUS seems to always return 0,
|
||||
* so we have to use fixed delay here.
|
||||
*/
|
||||
msleep(1);
|
||||
}
|
||||
|
||||
static void dss_dpll_power_disable(struct dss_video_pll *vpll)
|
||||
{
|
||||
REG_MOD(vpll->clkctrl_base, 0, 31, 30); /* PLL_POWER_OFF */
|
||||
}
|
||||
|
||||
static int dss_video_pll_enable(struct dss_pll *pll)
|
||||
{
|
||||
struct dss_video_pll *vpll = container_of(pll, struct dss_video_pll, pll);
|
||||
int r;
|
||||
|
||||
r = dss_runtime_get();
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dss_ctrl_pll_enable(pll->id, true);
|
||||
|
||||
dss_dpll_enable_scp_clk(vpll);
|
||||
|
||||
r = dss_pll_wait_reset_done(pll);
|
||||
if (r)
|
||||
goto err_reset;
|
||||
|
||||
dss_dpll_power_enable(vpll);
|
||||
|
||||
return 0;
|
||||
|
||||
err_reset:
|
||||
dss_dpll_disable_scp_clk(vpll);
|
||||
dss_ctrl_pll_enable(pll->id, false);
|
||||
dss_runtime_put();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void dss_video_pll_disable(struct dss_pll *pll)
|
||||
{
|
||||
struct dss_video_pll *vpll = container_of(pll, struct dss_video_pll, pll);
|
||||
|
||||
dss_dpll_power_disable(vpll);
|
||||
|
||||
dss_dpll_disable_scp_clk(vpll);
|
||||
|
||||
dss_ctrl_pll_enable(pll->id, false);
|
||||
|
||||
dss_runtime_put();
|
||||
}
|
||||
|
||||
static const struct dss_pll_ops dss_pll_ops = {
|
||||
.enable = dss_video_pll_enable,
|
||||
.disable = dss_video_pll_disable,
|
||||
.set_config = dss_pll_write_config_type_a,
|
||||
};
|
||||
|
||||
static const struct dss_pll_hw dss_dra7_video_pll_hw = {
|
||||
.n_max = (1 << 8) - 1,
|
||||
.m_max = (1 << 12) - 1,
|
||||
.mX_max = (1 << 5) - 1,
|
||||
.fint_min = 500000,
|
||||
.fint_max = 2500000,
|
||||
.clkdco_max = 1800000000,
|
||||
|
||||
.n_msb = 8,
|
||||
.n_lsb = 1,
|
||||
.m_msb = 20,
|
||||
.m_lsb = 9,
|
||||
|
||||
.mX_msb[0] = 25,
|
||||
.mX_lsb[0] = 21,
|
||||
.mX_msb[1] = 30,
|
||||
.mX_lsb[1] = 26,
|
||||
|
||||
.has_refsel = true,
|
||||
};
|
||||
|
||||
struct dss_pll *dss_video_pll_init(struct platform_device *pdev, int id,
|
||||
struct regulator *regulator)
|
||||
{
|
||||
const char * const reg_name[] = { "pll1", "pll2" };
|
||||
const char * const clkctrl_name[] = { "pll1_clkctrl", "pll2_clkctrl" };
|
||||
const char * const clkin_name[] = { "video1_clk", "video2_clk" };
|
||||
|
||||
struct resource *res;
|
||||
struct dss_video_pll *vpll;
|
||||
void __iomem *pll_base, *clkctrl_base;
|
||||
struct clk *clk;
|
||||
struct dss_pll *pll;
|
||||
int r;
|
||||
|
||||
/* PLL CONTROL */
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, reg_name[id]);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev,
|
||||
"missing platform resource data for pll%d\n", id);
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
pll_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(pll_base)) {
|
||||
dev_err(&pdev->dev, "failed to ioremap pll%d reg_name\n", id);
|
||||
return ERR_CAST(pll_base);
|
||||
}
|
||||
|
||||
/* CLOCK CONTROL */
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||
clkctrl_name[id]);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev,
|
||||
"missing platform resource data for pll%d\n", id);
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
clkctrl_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(clkctrl_base)) {
|
||||
dev_err(&pdev->dev, "failed to ioremap pll%d clkctrl\n", id);
|
||||
return ERR_CAST(clkctrl_base);
|
||||
}
|
||||
|
||||
/* CLKIN */
|
||||
|
||||
clk = devm_clk_get(&pdev->dev, clkin_name[id]);
|
||||
if (IS_ERR(clk)) {
|
||||
DSSERR("can't get video pll clkin\n");
|
||||
return ERR_CAST(clk);
|
||||
}
|
||||
|
||||
vpll = devm_kzalloc(&pdev->dev, sizeof(*vpll), GFP_KERNEL);
|
||||
if (!vpll)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
vpll->dev = &pdev->dev;
|
||||
vpll->clkctrl_base = clkctrl_base;
|
||||
|
||||
pll = &vpll->pll;
|
||||
|
||||
pll->name = id == 0 ? "video0" : "video1";
|
||||
pll->id = id == 0 ? DSS_PLL_VIDEO1 : DSS_PLL_VIDEO2;
|
||||
pll->clkin = clk;
|
||||
pll->regulator = regulator;
|
||||
pll->base = pll_base;
|
||||
pll->hw = &dss_dra7_video_pll_hw;
|
||||
pll->ops = &dss_pll_ops;
|
||||
|
||||
r = dss_pll_register(pll);
|
||||
if (r)
|
||||
return ERR_PTR(r);
|
||||
|
||||
return pll;
|
||||
}
|
||||
|
||||
void dss_video_pll_uninit(struct dss_pll *pll)
|
||||
{
|
||||
dss_pll_unregister(pll);
|
||||
}
|
@ -137,8 +137,11 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
|
||||
goto undo;
|
||||
}
|
||||
|
||||
if (ovl->manager)
|
||||
ovl->manager->apply(ovl->manager);
|
||||
if (ovl->manager) {
|
||||
r = ovl->manager->apply(ovl->manager);
|
||||
if (r)
|
||||
goto undo;
|
||||
}
|
||||
|
||||
if (pi->enabled) {
|
||||
r = ovl->enable(ovl);
|
||||
|
@ -314,6 +314,7 @@ enum omapdss_version {
|
||||
OMAPDSS_VER_OMAP4, /* All other OMAP4s */
|
||||
OMAPDSS_VER_OMAP5,
|
||||
OMAPDSS_VER_AM43xx,
|
||||
OMAPDSS_VER_DRA7xx,
|
||||
};
|
||||
|
||||
/* Board specific data */
|
||||
|
Loading…
Reference in New Issue
Block a user