omapdrm changes for 5.2
- Implement drm_bridge and drm_panel support for omapdrm - Drop omapdrm's panel-dpi, tfp410 and connector-dvi drivers - New DRM_BUS_FLAG_*_(DRIVE|SAMPLE)_(POS|NEG)EDGE flags - Improvements to tfp410 driver - OSD070T1718-19TS panel support to simple-panel - panel-tpo-td028ttec1 backlight support -----BEGIN PGP SIGNATURE----- iQJKBAABCgA0FiEExDgMPpZe/YEHn/On+j2qjLyWHvUFAlyPaacWHHRvbWkudmFs a2VpbmVuQHRpLmNvbQAKCRD6PaqMvJYe9STCD/sFasy7SrjqfmvJlEwIEK/ppZip hPnJdJVkrSiduhLsL8awPnxwKuK11bxSi1Tqiy/VFMNP+oYJGFWnINriHmtzvLui 65SNTjhMKs9iw2PLpjkNHh+iMVcn3NBzUVmzd/qMIlL/pQ23pWDKgYOcWQFuzqXC I255VAr3e0c2VNwbSv4HbpdsaECTpJ/GfYPtN09Io49UDa0pdshyN4j4Q54tlL8D e28ahnS5zuM9lJmyeRxpZl1qVeELFosoIqiqoa6gfCqBV7FZrDyx4D7IKiAzXHy2 U8yDA5Lvlwk8G+F/bxnqMIlRnSGJenAviO+VS0TVk4LVPdJ5Lg7YQJoTAsHgyPNt KbU+lKHszpqmcAuGL9p9rFE6qpcTft0e1hicmrCztG3O5g/Z7JEx4C8EAmmr35Z/ N2LGOCqwpAcNntCIepc3EHqDSamzODND8TK5dCdA2RnkOMyalyIVY5nqzg9I7WeM 9k/RAQF4ADpZDycrtxr9DF/z/H+ihvFZjAdmc0gbSoyBiqJzsKUSUTzUIUIArHT9 T30dlTzb/7gg0roSFza8F1H8JvDM+0Wj4U/QUYQfoGDWDGF2EpoNaNILo5/gbBpd EIRxu+itCA9BRe8hu2ZYjySNdKbfS+XqJ29uGwpkbHJHaKiWDhwaWJC6cZsaDF9o 2w20M0mwpeAaM9opMQ== =hS+k -----END PGP SIGNATURE----- Merge tag 'omapdrm-5.2' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux into drm-next omapdrm changes for 5.2 - Implement drm_bridge and drm_panel support for omapdrm - Drop omapdrm's panel-dpi, tfp410 and connector-dvi drivers - New DRM_BUS_FLAG_*_(DRIVE|SAMPLE)_(POS|NEG)EDGE flags - Improvements to tfp410 driver - OSD070T1718-19TS panel support to simple-panel - panel-tpo-td028ttec1 backlight support Signed-off-by: Dave Airlie <airlied@redhat.com> From: Tomi Valkeinen <tomi.valkeinen@ti.com> Link: https://patchwork.freedesktop.org/patch/msgid/670dc1ce-feaf-b88e-780f-b99251b88a82@ti.com
This commit is contained in:
commit
b9e687fc0a
|
@ -6,15 +6,25 @@ Required properties:
|
|||
|
||||
Optional properties:
|
||||
- powerdown-gpios: power-down gpio
|
||||
- reg: I2C address. If and only if present the device node
|
||||
should be placed into the i2c controller node where the
|
||||
tfp410 i2c is connected to.
|
||||
- reg: I2C address. If and only if present the device node should be placed
|
||||
into the I2C controller node where the TFP410 I2C is connected to.
|
||||
- ti,deskew: data de-skew in 350ps increments, from -4 to +3, as configured
|
||||
through th DK[3:1] pins. This property shall be present only if the TFP410
|
||||
is not connected through I2C.
|
||||
|
||||
Required nodes:
|
||||
- Video port 0 for DPI input [1].
|
||||
- Video port 1 for DVI output [1].
|
||||
|
||||
[1]: Documentation/devicetree/bindings/media/video-interfaces.txt
|
||||
This device has two video ports. Their connections are modeled using the OF
|
||||
graph bindings specified in [1]. Each port node shall have a single endpoint.
|
||||
|
||||
- Port 0 is the DPI input port. Its endpoint subnode shall contain a
|
||||
pclk-sample property and a remote-endpoint property as specified in [1].
|
||||
|
||||
- Port 1 is the DVI output port. Its endpoint subnode shall contain a
|
||||
remote-endpoint property is specified in [1].
|
||||
|
||||
[1] Documentation/devicetree/bindings/media/video-interfaces.txt
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
@ -22,6 +32,7 @@ Example
|
|||
tfp410: encoder@0 {
|
||||
compatible = "ti,tfp410";
|
||||
powerdown-gpios = <&twl_gpio 2 GPIO_ACTIVE_LOW>;
|
||||
ti,deskew = <4>;
|
||||
|
||||
ports {
|
||||
#address-cells = <1>;
|
||||
|
@ -31,6 +42,7 @@ tfp410: encoder@0 {
|
|||
reg = <0>;
|
||||
|
||||
tfp410_in: endpoint@0 {
|
||||
pclk-sample = <1>;
|
||||
remote-endpoint = <&dpi_out>;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
OSD Displays OSD070T1718-19TS 7" WVGA TFT LCD panel
|
||||
|
||||
Required properties:
|
||||
- compatible: shall be "osddisplays,osd070t1718-19ts"
|
||||
- power-supply: see simple-panel.txt
|
||||
|
||||
Optional properties:
|
||||
- backlight: see simple-panel.txt
|
||||
|
||||
This binding is compatible with the simple-panel binding, which is specified
|
||||
in simple-panel.txt in this directory. No other simple-panel properties than
|
||||
the ones specified herein are valid.
|
|
@ -6,6 +6,7 @@ Required properties:
|
|||
|
||||
Optional properties:
|
||||
- label: a symbolic name for the panel
|
||||
- backlight: phandle of the backlight device
|
||||
|
||||
Required nodes:
|
||||
- Video port for DPI input
|
||||
|
@ -21,6 +22,7 @@ lcd-panel: td028ttec1@0 {
|
|||
spi-cpha;
|
||||
|
||||
label = "lcd";
|
||||
backlight = <&backlight>;
|
||||
port {
|
||||
lcd_in: endpoint {
|
||||
remote-endpoint = <&dpi_out>;
|
||||
|
|
|
@ -302,6 +302,7 @@ oranth Shenzhen Oranth Technology Co., Ltd.
|
|||
ORCL Oracle Corporation
|
||||
orisetech Orise Technology
|
||||
ortustech Ortus Technology Co., Ltd.
|
||||
osddisplays OSD Displays
|
||||
ovti OmniVision Technologies
|
||||
oxsemi Oxford Semiconductor, Ltd.
|
||||
panasonic Panasonic Corporation
|
||||
|
|
|
@ -234,7 +234,7 @@ static int dumb_vga_remove(struct platform_device *pdev)
|
|||
*/
|
||||
static const struct drm_bridge_timings default_dac_timings = {
|
||||
/* Timing specifications, datasheet page 7 */
|
||||
.sampling_edge = DRM_BUS_FLAG_PIXDATA_POSEDGE,
|
||||
.input_bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE,
|
||||
.setup_time_ps = 500,
|
||||
.hold_time_ps = 1500,
|
||||
};
|
||||
|
@ -245,7 +245,7 @@ static const struct drm_bridge_timings default_dac_timings = {
|
|||
*/
|
||||
static const struct drm_bridge_timings ti_ths8134_dac_timings = {
|
||||
/* From timing diagram, datasheet page 9 */
|
||||
.sampling_edge = DRM_BUS_FLAG_PIXDATA_POSEDGE,
|
||||
.input_bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE,
|
||||
/* From datasheet, page 12 */
|
||||
.setup_time_ps = 3000,
|
||||
/* I guess this means latched input */
|
||||
|
@ -258,7 +258,7 @@ static const struct drm_bridge_timings ti_ths8134_dac_timings = {
|
|||
*/
|
||||
static const struct drm_bridge_timings ti_ths8135_dac_timings = {
|
||||
/* From timing diagram, datasheet page 14 */
|
||||
.sampling_edge = DRM_BUS_FLAG_PIXDATA_POSEDGE,
|
||||
.input_bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE,
|
||||
/* From datasheet, page 16 */
|
||||
.setup_time_ps = 2000,
|
||||
.hold_time_ps = 500,
|
||||
|
|
|
@ -1222,8 +1222,8 @@ static int tc_bridge_attach(struct drm_bridge *bridge)
|
|||
&bus_format, 1);
|
||||
tc->connector.display_info.bus_flags =
|
||||
DRM_BUS_FLAG_DE_HIGH |
|
||||
DRM_BUS_FLAG_PIXDATA_NEGEDGE |
|
||||
DRM_BUS_FLAG_SYNC_NEGEDGE;
|
||||
DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE |
|
||||
DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE;
|
||||
drm_connector_attach_encoder(&tc->connector, tc->bridge.encoder);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -27,10 +27,14 @@
|
|||
struct tfp410 {
|
||||
struct drm_bridge bridge;
|
||||
struct drm_connector connector;
|
||||
unsigned int connector_type;
|
||||
|
||||
struct i2c_adapter *ddc;
|
||||
struct gpio_desc *hpd;
|
||||
struct delayed_work hpd_work;
|
||||
struct gpio_desc *powerdown;
|
||||
|
||||
struct drm_bridge_timings timings;
|
||||
|
||||
struct device *dev;
|
||||
};
|
||||
|
@ -126,7 +130,7 @@ static int tfp410_attach(struct drm_bridge *bridge)
|
|||
drm_connector_helper_add(&dvi->connector,
|
||||
&tfp410_con_helper_funcs);
|
||||
ret = drm_connector_init(bridge->dev, &dvi->connector,
|
||||
&tfp410_con_funcs, DRM_MODE_CONNECTOR_HDMIA);
|
||||
&tfp410_con_funcs, dvi->connector_type);
|
||||
if (ret) {
|
||||
dev_err(dvi->dev, "drm_connector_init() failed: %d\n", ret);
|
||||
return ret;
|
||||
|
@ -138,8 +142,24 @@ static int tfp410_attach(struct drm_bridge *bridge)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void tfp410_enable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct tfp410 *dvi = drm_bridge_to_tfp410(bridge);
|
||||
|
||||
gpiod_set_value_cansleep(dvi->powerdown, 0);
|
||||
}
|
||||
|
||||
static void tfp410_disable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct tfp410 *dvi = drm_bridge_to_tfp410(bridge);
|
||||
|
||||
gpiod_set_value_cansleep(dvi->powerdown, 1);
|
||||
}
|
||||
|
||||
static const struct drm_bridge_funcs tfp410_bridge_funcs = {
|
||||
.attach = tfp410_attach,
|
||||
.enable = tfp410_enable,
|
||||
.disable = tfp410_disable,
|
||||
};
|
||||
|
||||
static void tfp410_hpd_work_func(struct work_struct *work)
|
||||
|
@ -162,6 +182,70 @@ static irqreturn_t tfp410_hpd_irq_thread(int irq, void *arg)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static const struct drm_bridge_timings tfp410_default_timings = {
|
||||
.input_bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE
|
||||
| DRM_BUS_FLAG_DE_HIGH,
|
||||
.setup_time_ps = 1200,
|
||||
.hold_time_ps = 1300,
|
||||
};
|
||||
|
||||
static int tfp410_parse_timings(struct tfp410 *dvi, bool i2c)
|
||||
{
|
||||
struct drm_bridge_timings *timings = &dvi->timings;
|
||||
struct device_node *ep;
|
||||
u32 pclk_sample = 0;
|
||||
s32 deskew = 0;
|
||||
|
||||
/* Start with defaults. */
|
||||
*timings = tfp410_default_timings;
|
||||
|
||||
if (i2c)
|
||||
/*
|
||||
* In I2C mode timings are configured through the I2C interface.
|
||||
* As the driver doesn't support I2C configuration yet, we just
|
||||
* go with the defaults (BSEL=1, DSEL=1, DKEN=0, EDGE=1).
|
||||
*/
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* In non-I2C mode, timings are configured through the BSEL, DSEL, DKEN
|
||||
* and EDGE pins. They are specified in DT through endpoint properties
|
||||
* and vendor-specific properties.
|
||||
*/
|
||||
ep = of_graph_get_endpoint_by_regs(dvi->dev->of_node, 0, 0);
|
||||
if (!ep)
|
||||
return -EINVAL;
|
||||
|
||||
/* Get the sampling edge from the endpoint. */
|
||||
of_property_read_u32(ep, "pclk-sample", &pclk_sample);
|
||||
of_node_put(ep);
|
||||
|
||||
timings->input_bus_flags = DRM_BUS_FLAG_DE_HIGH;
|
||||
|
||||
switch (pclk_sample) {
|
||||
case 0:
|
||||
timings->input_bus_flags |= DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE
|
||||
| DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE;
|
||||
break;
|
||||
case 1:
|
||||
timings->input_bus_flags |= DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE
|
||||
| DRM_BUS_FLAG_SYNC_SAMPLE_POSEDGE;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Get the setup and hold time from vendor-specific properties. */
|
||||
of_property_read_u32(dvi->dev->of_node, "ti,deskew", (u32 *)&deskew);
|
||||
if (deskew < -4 || deskew > 3)
|
||||
return -EINVAL;
|
||||
|
||||
timings->setup_time_ps = min(0, 1200 - 350 * deskew);
|
||||
timings->hold_time_ps = min(0, 1300 + 350 * deskew);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tfp410_get_connector_properties(struct tfp410 *dvi)
|
||||
{
|
||||
struct device_node *connector_node, *ddc_phandle;
|
||||
|
@ -172,6 +256,11 @@ static int tfp410_get_connector_properties(struct tfp410 *dvi)
|
|||
if (!connector_node)
|
||||
return -ENODEV;
|
||||
|
||||
if (of_device_is_compatible(connector_node, "hdmi-connector"))
|
||||
dvi->connector_type = DRM_MODE_CONNECTOR_HDMIA;
|
||||
else
|
||||
dvi->connector_type = DRM_MODE_CONNECTOR_DVID;
|
||||
|
||||
dvi->hpd = fwnode_get_named_gpiod(&connector_node->fwnode,
|
||||
"hpd-gpios", 0, GPIOD_IN, "hpd");
|
||||
if (IS_ERR(dvi->hpd)) {
|
||||
|
@ -200,7 +289,7 @@ fail:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int tfp410_init(struct device *dev)
|
||||
static int tfp410_init(struct device *dev, bool i2c)
|
||||
{
|
||||
struct tfp410 *dvi;
|
||||
int ret;
|
||||
|
@ -217,12 +306,24 @@ static int tfp410_init(struct device *dev)
|
|||
|
||||
dvi->bridge.funcs = &tfp410_bridge_funcs;
|
||||
dvi->bridge.of_node = dev->of_node;
|
||||
dvi->bridge.timings = &dvi->timings;
|
||||
dvi->dev = dev;
|
||||
|
||||
ret = tfp410_parse_timings(dvi, i2c);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
ret = tfp410_get_connector_properties(dvi);
|
||||
if (ret)
|
||||
goto fail;
|
||||
|
||||
dvi->powerdown = devm_gpiod_get_optional(dev, "powerdown",
|
||||
GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(dvi->powerdown)) {
|
||||
dev_err(dev, "failed to parse powerdown gpio\n");
|
||||
return PTR_ERR(dvi->powerdown);
|
||||
}
|
||||
|
||||
if (dvi->hpd) {
|
||||
INIT_DELAYED_WORK(&dvi->hpd_work, tfp410_hpd_work_func);
|
||||
|
||||
|
@ -264,7 +365,7 @@ static int tfp410_fini(struct device *dev)
|
|||
|
||||
static int tfp410_probe(struct platform_device *pdev)
|
||||
{
|
||||
return tfp410_init(&pdev->dev);
|
||||
return tfp410_init(&pdev->dev, false);
|
||||
}
|
||||
|
||||
static int tfp410_remove(struct platform_device *pdev)
|
||||
|
@ -301,7 +402,7 @@ static int tfp410_i2c_probe(struct i2c_client *client,
|
|||
return -ENXIO;
|
||||
}
|
||||
|
||||
return tfp410_init(&client->dev);
|
||||
return tfp410_init(&client->dev, true);
|
||||
}
|
||||
|
||||
static int tfp410_i2c_remove(struct i2c_client *client)
|
||||
|
|
|
@ -495,7 +495,7 @@ mode_fixup(struct drm_atomic_state *state)
|
|||
static enum drm_mode_status mode_valid_path(struct drm_connector *connector,
|
||||
struct drm_encoder *encoder,
|
||||
struct drm_crtc *crtc,
|
||||
struct drm_display_mode *mode)
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
enum drm_mode_status ret;
|
||||
|
||||
|
@ -534,7 +534,7 @@ mode_valid(struct drm_atomic_state *state)
|
|||
struct drm_crtc *crtc = conn_state->crtc;
|
||||
struct drm_crtc_state *crtc_state;
|
||||
enum drm_mode_status mode_status;
|
||||
struct drm_display_mode *mode;
|
||||
const struct drm_display_mode *mode;
|
||||
|
||||
if (!crtc || !encoder)
|
||||
continue;
|
||||
|
|
|
@ -655,22 +655,22 @@ EXPORT_SYMBOL_GPL(drm_display_mode_to_videomode);
|
|||
* @bus_flags: information about pixelclk, sync and DE polarity will be stored
|
||||
* here
|
||||
*
|
||||
* Sets DRM_BUS_FLAG_DE_(LOW|HIGH), DRM_BUS_FLAG_PIXDATA_(POS|NEG)EDGE and
|
||||
* DISPLAY_FLAGS_SYNC_(POS|NEG)EDGE in @bus_flags according to DISPLAY_FLAGS
|
||||
* Sets DRM_BUS_FLAG_DE_(LOW|HIGH), DRM_BUS_FLAG_PIXDATA_DRIVE_(POS|NEG)EDGE
|
||||
* and DISPLAY_FLAGS_SYNC_(POS|NEG)EDGE in @bus_flags according to DISPLAY_FLAGS
|
||||
* found in @vm
|
||||
*/
|
||||
void drm_bus_flags_from_videomode(const struct videomode *vm, u32 *bus_flags)
|
||||
{
|
||||
*bus_flags = 0;
|
||||
if (vm->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE)
|
||||
*bus_flags |= DRM_BUS_FLAG_PIXDATA_POSEDGE;
|
||||
*bus_flags |= DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE;
|
||||
if (vm->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
|
||||
*bus_flags |= DRM_BUS_FLAG_PIXDATA_NEGEDGE;
|
||||
*bus_flags |= DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE;
|
||||
|
||||
if (vm->flags & DISPLAY_FLAGS_SYNC_POSEDGE)
|
||||
*bus_flags |= DRM_BUS_FLAG_SYNC_POSEDGE;
|
||||
*bus_flags |= DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE;
|
||||
if (vm->flags & DISPLAY_FLAGS_SYNC_NEGEDGE)
|
||||
*bus_flags |= DRM_BUS_FLAG_SYNC_NEGEDGE;
|
||||
*bus_flags |= DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE;
|
||||
|
||||
if (vm->flags & DISPLAY_FLAGS_DE_LOW)
|
||||
*bus_flags |= DRM_BUS_FLAG_DE_LOW;
|
||||
|
|
|
@ -94,7 +94,7 @@ static void fsl_dcu_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
|
|||
drm_display_mode_to_videomode(mode, &vm);
|
||||
|
||||
/* INV_PXCK as default (most display sample data on rising edge) */
|
||||
if (!(con->display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_POSEDGE))
|
||||
if (!(con->display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE))
|
||||
pol |= DCU_SYN_POL_INV_PXCK;
|
||||
|
||||
if (vm.flags & DISPLAY_FLAGS_HSYNC_LOW)
|
||||
|
|
|
@ -295,7 +295,7 @@ static void ipu_crtc_mode_set_nofb(struct drm_crtc *crtc)
|
|||
sig_cfg.enable_pol = !(imx_crtc_state->bus_flags & DRM_BUS_FLAG_DE_LOW);
|
||||
/* Default to driving pixel data on negative clock edges */
|
||||
sig_cfg.clk_pol = !!(imx_crtc_state->bus_flags &
|
||||
DRM_BUS_FLAG_PIXDATA_POSEDGE);
|
||||
DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE);
|
||||
sig_cfg.bus_format = imx_crtc_state->bus_format;
|
||||
sig_cfg.v_to_h_sync = 0;
|
||||
sig_cfg.hsync_pin = imx_crtc_state->di_hsync_pin;
|
||||
|
|
|
@ -253,12 +253,12 @@ static void mxsfb_crtc_mode_set_nofb(struct mxsfb_drm_private *mxsfb)
|
|||
if (!(bus_flags & DRM_BUS_FLAG_DE_LOW))
|
||||
vdctrl0 |= VDCTRL0_ENABLE_ACT_HIGH;
|
||||
/*
|
||||
* DRM_BUS_FLAG_PIXDATA_ defines are controller centric,
|
||||
* DRM_BUS_FLAG_PIXDATA_DRIVE_ defines are controller centric,
|
||||
* controllers VDCTRL0_DOTCLK is display centric.
|
||||
* Drive on positive edge -> display samples on falling edge
|
||||
* DRM_BUS_FLAG_PIXDATA_POSEDGE -> VDCTRL0_DOTCLK_ACT_FALLING
|
||||
* DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE -> VDCTRL0_DOTCLK_ACT_FALLING
|
||||
*/
|
||||
if (bus_flags & DRM_BUS_FLAG_PIXDATA_POSEDGE)
|
||||
if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE)
|
||||
vdctrl0 |= VDCTRL0_DOTCLK_ACT_FALLING;
|
||||
|
||||
writel(vdctrl0, mxsfb->base + LCDC_VDCTRL0);
|
||||
|
|
|
@ -6,23 +6,12 @@ config DRM_OMAP_ENCODER_OPA362
|
|||
Driver for OPA362 external analog TV amplifier controlled
|
||||
through a GPIO.
|
||||
|
||||
config DRM_OMAP_ENCODER_TFP410
|
||||
tristate "TFP410 DPI to DVI Encoder"
|
||||
help
|
||||
Driver for TFP410 DPI to DVI encoder.
|
||||
|
||||
config DRM_OMAP_ENCODER_TPD12S015
|
||||
tristate "TPD12S015 HDMI ESD protection and level shifter"
|
||||
help
|
||||
Driver for TPD12S015, which offers HDMI ESD protection and level
|
||||
shifting.
|
||||
|
||||
config DRM_OMAP_CONNECTOR_DVI
|
||||
tristate "DVI Connector"
|
||||
depends on I2C
|
||||
help
|
||||
Driver for a generic DVI connector.
|
||||
|
||||
config DRM_OMAP_CONNECTOR_HDMI
|
||||
tristate "HDMI Connector"
|
||||
help
|
||||
|
@ -33,12 +22,6 @@ config DRM_OMAP_CONNECTOR_ANALOG_TV
|
|||
help
|
||||
Driver for a generic analog TV connector.
|
||||
|
||||
config DRM_OMAP_PANEL_DPI
|
||||
tristate "Generic DPI panel"
|
||||
depends on BACKLIGHT_CLASS_DEVICE
|
||||
help
|
||||
Driver for generic DPI panels.
|
||||
|
||||
config DRM_OMAP_PANEL_DSI_CM
|
||||
tristate "Generic DSI Command Mode Panel"
|
||||
depends on BACKLIGHT_CLASS_DEVICE
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
obj-$(CONFIG_DRM_OMAP_ENCODER_OPA362) += encoder-opa362.o
|
||||
obj-$(CONFIG_DRM_OMAP_ENCODER_TFP410) += encoder-tfp410.o
|
||||
obj-$(CONFIG_DRM_OMAP_ENCODER_TPD12S015) += encoder-tpd12s015.o
|
||||
obj-$(CONFIG_DRM_OMAP_CONNECTOR_DVI) += connector-dvi.o
|
||||
obj-$(CONFIG_DRM_OMAP_CONNECTOR_HDMI) += connector-hdmi.o
|
||||
obj-$(CONFIG_DRM_OMAP_CONNECTOR_ANALOG_TV) += connector-analog-tv.o
|
||||
obj-$(CONFIG_DRM_OMAP_PANEL_DPI) += panel-dpi.o
|
||||
obj-$(CONFIG_DRM_OMAP_PANEL_DSI_CM) += panel-dsi-cm.o
|
||||
obj-$(CONFIG_DRM_OMAP_PANEL_SONY_ACX565AKM) += panel-sony-acx565akm.o
|
||||
obj-$(CONFIG_DRM_OMAP_PANEL_LGPHILIPS_LB035Q02) += panel-lgphilips-lb035q02.o
|
||||
|
|
|
@ -35,50 +35,9 @@ static void tvc_disconnect(struct omap_dss_device *src,
|
|||
{
|
||||
}
|
||||
|
||||
static int tvc_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *src = dssdev->src;
|
||||
int r;
|
||||
|
||||
dev_dbg(ddata->dev, "enable\n");
|
||||
|
||||
if (!omapdss_device_is_connected(dssdev))
|
||||
return -ENODEV;
|
||||
|
||||
if (omapdss_device_is_enabled(dssdev))
|
||||
return 0;
|
||||
|
||||
r = src->ops->enable(src);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void tvc_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *src = dssdev->src;
|
||||
|
||||
dev_dbg(ddata->dev, "disable\n");
|
||||
|
||||
if (!omapdss_device_is_enabled(dssdev))
|
||||
return;
|
||||
|
||||
src->ops->disable(src);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
|
||||
}
|
||||
|
||||
static const struct omap_dss_device_ops tvc_ops = {
|
||||
.connect = tvc_connect,
|
||||
.disconnect = tvc_disconnect,
|
||||
|
||||
.enable = tvc_enable,
|
||||
.disable = tvc_disable,
|
||||
};
|
||||
|
||||
static int tvc_probe(struct platform_device *pdev)
|
||||
|
@ -97,6 +56,7 @@ static int tvc_probe(struct platform_device *pdev)
|
|||
dssdev->ops = &tvc_ops;
|
||||
dssdev->dev = &pdev->dev;
|
||||
dssdev->type = OMAP_DISPLAY_TYPE_VENC;
|
||||
dssdev->display = true;
|
||||
dssdev->owner = THIS_MODULE;
|
||||
dssdev->of_ports = BIT(0);
|
||||
|
||||
|
@ -109,12 +69,9 @@ static int tvc_probe(struct platform_device *pdev)
|
|||
static int __exit tvc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
|
||||
struct omap_dss_device *dssdev = &ddata->dssdev;
|
||||
|
||||
omapdss_device_unregister(&ddata->dssdev);
|
||||
|
||||
tvc_disable(dssdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,330 +0,0 @@
|
|||
/*
|
||||
* Generic DVI Connector driver
|
||||
*
|
||||
* Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
|
||||
* 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/consumer.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <drm/drm_edid.h>
|
||||
|
||||
#include "../dss/omapdss.h"
|
||||
|
||||
struct panel_drv_data {
|
||||
struct omap_dss_device dssdev;
|
||||
|
||||
struct i2c_adapter *i2c_adapter;
|
||||
|
||||
struct gpio_desc *hpd_gpio;
|
||||
|
||||
void (*hpd_cb)(void *cb_data, enum drm_connector_status status);
|
||||
void *hpd_cb_data;
|
||||
bool hpd_enabled;
|
||||
/* mutex for hpd fields above */
|
||||
struct mutex hpd_lock;
|
||||
};
|
||||
|
||||
#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
|
||||
|
||||
static int dvic_connect(struct omap_dss_device *src,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dvic_disconnect(struct omap_dss_device *src,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
}
|
||||
|
||||
static int dvic_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_dss_device *src = dssdev->src;
|
||||
int r;
|
||||
|
||||
if (!omapdss_device_is_connected(dssdev))
|
||||
return -ENODEV;
|
||||
|
||||
if (omapdss_device_is_enabled(dssdev))
|
||||
return 0;
|
||||
|
||||
r = src->ops->enable(src);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dvic_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_dss_device *src = dssdev->src;
|
||||
|
||||
if (!omapdss_device_is_enabled(dssdev))
|
||||
return;
|
||||
|
||||
src->ops->disable(src);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
|
||||
}
|
||||
|
||||
static int dvic_ddc_read(struct i2c_adapter *adapter,
|
||||
unsigned char *buf, u16 count, u8 offset)
|
||||
{
|
||||
int r, retries;
|
||||
|
||||
for (retries = 3; retries > 0; retries--) {
|
||||
struct i2c_msg msgs[] = {
|
||||
{
|
||||
.addr = DDC_ADDR,
|
||||
.flags = 0,
|
||||
.len = 1,
|
||||
.buf = &offset,
|
||||
}, {
|
||||
.addr = DDC_ADDR,
|
||||
.flags = I2C_M_RD,
|
||||
.len = count,
|
||||
.buf = buf,
|
||||
}
|
||||
};
|
||||
|
||||
r = i2c_transfer(adapter, msgs, 2);
|
||||
if (r == 2)
|
||||
return 0;
|
||||
|
||||
if (r != -EAGAIN)
|
||||
break;
|
||||
}
|
||||
|
||||
return r < 0 ? r : -EIO;
|
||||
}
|
||||
|
||||
static int dvic_read_edid(struct omap_dss_device *dssdev,
|
||||
u8 *edid, int len)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
int r, l, bytes_read;
|
||||
|
||||
l = min(EDID_LENGTH, len);
|
||||
r = dvic_ddc_read(ddata->i2c_adapter, edid, l, 0);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
bytes_read = l;
|
||||
|
||||
/* if there are extensions, read second block */
|
||||
if (len > EDID_LENGTH && edid[0x7e] > 0) {
|
||||
l = min(EDID_LENGTH, len - EDID_LENGTH);
|
||||
|
||||
r = dvic_ddc_read(ddata->i2c_adapter, edid + EDID_LENGTH,
|
||||
l, EDID_LENGTH);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
bytes_read += l;
|
||||
}
|
||||
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
static bool dvic_detect(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
unsigned char out;
|
||||
int r;
|
||||
|
||||
if (ddata->hpd_gpio)
|
||||
return gpiod_get_value_cansleep(ddata->hpd_gpio);
|
||||
|
||||
if (!ddata->i2c_adapter)
|
||||
return true;
|
||||
|
||||
r = dvic_ddc_read(ddata->i2c_adapter, &out, 1, 0);
|
||||
|
||||
return r == 0;
|
||||
}
|
||||
|
||||
static void dvic_register_hpd_cb(struct omap_dss_device *dssdev,
|
||||
void (*cb)(void *cb_data,
|
||||
enum drm_connector_status status),
|
||||
void *cb_data)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
|
||||
mutex_lock(&ddata->hpd_lock);
|
||||
ddata->hpd_cb = cb;
|
||||
ddata->hpd_cb_data = cb_data;
|
||||
mutex_unlock(&ddata->hpd_lock);
|
||||
}
|
||||
|
||||
static void dvic_unregister_hpd_cb(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
|
||||
mutex_lock(&ddata->hpd_lock);
|
||||
ddata->hpd_cb = NULL;
|
||||
ddata->hpd_cb_data = NULL;
|
||||
mutex_unlock(&ddata->hpd_lock);
|
||||
}
|
||||
|
||||
static const struct omap_dss_device_ops dvic_ops = {
|
||||
.connect = dvic_connect,
|
||||
.disconnect = dvic_disconnect,
|
||||
|
||||
.enable = dvic_enable,
|
||||
.disable = dvic_disable,
|
||||
|
||||
.read_edid = dvic_read_edid,
|
||||
.detect = dvic_detect,
|
||||
|
||||
.register_hpd_cb = dvic_register_hpd_cb,
|
||||
.unregister_hpd_cb = dvic_unregister_hpd_cb,
|
||||
};
|
||||
|
||||
static irqreturn_t dvic_hpd_isr(int irq, void *data)
|
||||
{
|
||||
struct panel_drv_data *ddata = data;
|
||||
|
||||
mutex_lock(&ddata->hpd_lock);
|
||||
if (ddata->hpd_enabled && ddata->hpd_cb) {
|
||||
enum drm_connector_status status;
|
||||
|
||||
if (dvic_detect(&ddata->dssdev))
|
||||
status = connector_status_connected;
|
||||
else
|
||||
status = connector_status_disconnected;
|
||||
|
||||
ddata->hpd_cb(ddata->hpd_cb_data, status);
|
||||
}
|
||||
mutex_unlock(&ddata->hpd_lock);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int dvic_probe_of(struct platform_device *pdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
struct device_node *adapter_node;
|
||||
struct i2c_adapter *adapter;
|
||||
struct gpio_desc *gpio;
|
||||
int r;
|
||||
|
||||
gpio = devm_gpiod_get_optional(&pdev->dev, "hpd", GPIOD_IN);
|
||||
if (IS_ERR(gpio)) {
|
||||
dev_err(&pdev->dev, "failed to parse HPD gpio\n");
|
||||
return PTR_ERR(gpio);
|
||||
}
|
||||
|
||||
ddata->hpd_gpio = gpio;
|
||||
|
||||
mutex_init(&ddata->hpd_lock);
|
||||
|
||||
if (ddata->hpd_gpio) {
|
||||
r = devm_request_threaded_irq(&pdev->dev,
|
||||
gpiod_to_irq(ddata->hpd_gpio), NULL, dvic_hpd_isr,
|
||||
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
|
||||
"DVI HPD", ddata);
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
|
||||
adapter_node = of_parse_phandle(node, "ddc-i2c-bus", 0);
|
||||
if (adapter_node) {
|
||||
adapter = of_get_i2c_adapter_by_node(adapter_node);
|
||||
of_node_put(adapter_node);
|
||||
if (adapter == NULL) {
|
||||
dev_err(&pdev->dev, "failed to parse ddc-i2c-bus\n");
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
ddata->i2c_adapter = adapter;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dvic_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct panel_drv_data *ddata;
|
||||
struct omap_dss_device *dssdev;
|
||||
int r;
|
||||
|
||||
ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
|
||||
if (!ddata)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, ddata);
|
||||
|
||||
r = dvic_probe_of(pdev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dssdev = &ddata->dssdev;
|
||||
dssdev->ops = &dvic_ops;
|
||||
dssdev->dev = &pdev->dev;
|
||||
dssdev->type = OMAP_DISPLAY_TYPE_DVI;
|
||||
dssdev->owner = THIS_MODULE;
|
||||
dssdev->of_ports = BIT(0);
|
||||
|
||||
if (ddata->hpd_gpio)
|
||||
dssdev->ops_flags |= OMAP_DSS_DEVICE_OP_DETECT
|
||||
| OMAP_DSS_DEVICE_OP_HPD;
|
||||
if (ddata->i2c_adapter)
|
||||
dssdev->ops_flags |= OMAP_DSS_DEVICE_OP_DETECT
|
||||
| OMAP_DSS_DEVICE_OP_EDID;
|
||||
|
||||
omapdss_display_init(dssdev);
|
||||
omapdss_device_register(dssdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __exit dvic_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
|
||||
struct omap_dss_device *dssdev = &ddata->dssdev;
|
||||
|
||||
omapdss_device_unregister(&ddata->dssdev);
|
||||
|
||||
dvic_disable(dssdev);
|
||||
|
||||
i2c_put_adapter(ddata->i2c_adapter);
|
||||
|
||||
mutex_destroy(&ddata->hpd_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id dvic_of_match[] = {
|
||||
{ .compatible = "omapdss,dvi-connector", },
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, dvic_of_match);
|
||||
|
||||
static struct platform_driver dvi_connector_driver = {
|
||||
.probe = dvic_probe,
|
||||
.remove = __exit_p(dvic_remove),
|
||||
.driver = {
|
||||
.name = "connector-dvi",
|
||||
.of_match_table = dvic_of_match,
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(dvi_connector_driver);
|
||||
|
||||
MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
|
||||
MODULE_DESCRIPTION("Generic DVI Connector driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -41,44 +41,6 @@ static void hdmic_disconnect(struct omap_dss_device *src,
|
|||
{
|
||||
}
|
||||
|
||||
static int hdmic_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *src = dssdev->src;
|
||||
int r;
|
||||
|
||||
dev_dbg(ddata->dev, "enable\n");
|
||||
|
||||
if (!omapdss_device_is_connected(dssdev))
|
||||
return -ENODEV;
|
||||
|
||||
if (omapdss_device_is_enabled(dssdev))
|
||||
return 0;
|
||||
|
||||
r = src->ops->enable(src);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void hdmic_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *src = dssdev->src;
|
||||
|
||||
dev_dbg(ddata->dev, "disable\n");
|
||||
|
||||
if (!omapdss_device_is_enabled(dssdev))
|
||||
return;
|
||||
|
||||
src->ops->disable(src);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
|
||||
}
|
||||
|
||||
static bool hdmic_detect(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
|
@ -113,9 +75,6 @@ static const struct omap_dss_device_ops hdmic_ops = {
|
|||
.connect = hdmic_connect,
|
||||
.disconnect = hdmic_disconnect,
|
||||
|
||||
.enable = hdmic_enable,
|
||||
.disable = hdmic_disable,
|
||||
|
||||
.detect = hdmic_detect,
|
||||
.register_hpd_cb = hdmic_register_hpd_cb,
|
||||
.unregister_hpd_cb = hdmic_unregister_hpd_cb,
|
||||
|
@ -181,6 +140,7 @@ static int hdmic_probe(struct platform_device *pdev)
|
|||
dssdev->ops = &hdmic_ops;
|
||||
dssdev->dev = &pdev->dev;
|
||||
dssdev->type = OMAP_DISPLAY_TYPE_HDMI;
|
||||
dssdev->display = true;
|
||||
dssdev->owner = THIS_MODULE;
|
||||
dssdev->of_ports = BIT(0);
|
||||
dssdev->ops_flags = ddata->hpd_gpio
|
||||
|
@ -196,12 +156,9 @@ static int hdmic_probe(struct platform_device *pdev)
|
|||
static int __exit hdmic_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
|
||||
struct omap_dss_device *dssdev = &ddata->dssdev;
|
||||
|
||||
omapdss_device_unregister(&ddata->dssdev);
|
||||
|
||||
hdmic_disable(dssdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -41,48 +41,20 @@ static void opa362_disconnect(struct omap_dss_device *src,
|
|||
omapdss_device_disconnect(dst, dst->next);
|
||||
}
|
||||
|
||||
static int opa362_enable(struct omap_dss_device *dssdev)
|
||||
static void opa362_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *src = dssdev->src;
|
||||
int r;
|
||||
|
||||
dev_dbg(dssdev->dev, "enable\n");
|
||||
|
||||
if (!omapdss_device_is_connected(dssdev))
|
||||
return -ENODEV;
|
||||
|
||||
if (omapdss_device_is_enabled(dssdev))
|
||||
return 0;
|
||||
|
||||
r = src->ops->enable(src);
|
||||
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 *src = dssdev->src;
|
||||
|
||||
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);
|
||||
|
||||
src->ops->disable(src);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
|
||||
}
|
||||
|
||||
static const struct omap_dss_device_ops opa362_ops = {
|
||||
|
@ -116,7 +88,6 @@ static int opa362_probe(struct platform_device *pdev)
|
|||
dssdev->ops = &opa362_ops;
|
||||
dssdev->dev = &pdev->dev;
|
||||
dssdev->type = OMAP_DISPLAY_TYPE_VENC;
|
||||
dssdev->output_type = OMAP_DISPLAY_TYPE_VENC;
|
||||
dssdev->owner = THIS_MODULE;
|
||||
dssdev->of_ports = BIT(1) | BIT(0);
|
||||
|
||||
|
@ -141,13 +112,7 @@ static int __exit opa362_remove(struct platform_device *pdev)
|
|||
omapdss_device_put(dssdev->next);
|
||||
omapdss_device_unregister(&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))
|
||||
omapdss_device_disconnect(NULL, dssdev);
|
||||
opa362_disable(dssdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,170 +0,0 @@
|
|||
/*
|
||||
* TFP410 DPI-to-DVI encoder driver
|
||||
*
|
||||
* Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
|
||||
* 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/consumer.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "../dss/omapdss.h"
|
||||
|
||||
struct panel_drv_data {
|
||||
struct omap_dss_device dssdev;
|
||||
|
||||
struct gpio_desc *pd_gpio;
|
||||
};
|
||||
|
||||
#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
|
||||
|
||||
static int tfp410_connect(struct omap_dss_device *src,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
return omapdss_device_connect(dst->dss, dst, dst->next);
|
||||
}
|
||||
|
||||
static void tfp410_disconnect(struct omap_dss_device *src,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
omapdss_device_disconnect(dst, dst->next);
|
||||
}
|
||||
|
||||
static int tfp410_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *src = dssdev->src;
|
||||
int r;
|
||||
|
||||
if (!omapdss_device_is_connected(dssdev))
|
||||
return -ENODEV;
|
||||
|
||||
if (omapdss_device_is_enabled(dssdev))
|
||||
return 0;
|
||||
|
||||
r = src->ops->enable(src);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (ddata->pd_gpio)
|
||||
gpiod_set_value_cansleep(ddata->pd_gpio, 0);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tfp410_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *src = dssdev->src;
|
||||
|
||||
if (!omapdss_device_is_enabled(dssdev))
|
||||
return;
|
||||
|
||||
if (ddata->pd_gpio)
|
||||
gpiod_set_value_cansleep(ddata->pd_gpio, 0);
|
||||
|
||||
src->ops->disable(src);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
|
||||
}
|
||||
|
||||
static const struct omap_dss_device_ops tfp410_ops = {
|
||||
.connect = tfp410_connect,
|
||||
.disconnect = tfp410_disconnect,
|
||||
.enable = tfp410_enable,
|
||||
.disable = tfp410_disable,
|
||||
};
|
||||
|
||||
static int tfp410_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct panel_drv_data *ddata;
|
||||
struct omap_dss_device *dssdev;
|
||||
struct gpio_desc *gpio;
|
||||
|
||||
ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
|
||||
if (!ddata)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, ddata);
|
||||
|
||||
/* Powerdown GPIO */
|
||||
gpio = devm_gpiod_get_optional(&pdev->dev, "powerdown", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(gpio)) {
|
||||
dev_err(&pdev->dev, "failed to parse powerdown gpio\n");
|
||||
return PTR_ERR(gpio);
|
||||
}
|
||||
|
||||
ddata->pd_gpio = gpio;
|
||||
|
||||
dssdev = &ddata->dssdev;
|
||||
dssdev->ops = &tfp410_ops;
|
||||
dssdev->dev = &pdev->dev;
|
||||
dssdev->type = OMAP_DISPLAY_TYPE_DPI;
|
||||
dssdev->output_type = OMAP_DISPLAY_TYPE_DVI;
|
||||
dssdev->owner = THIS_MODULE;
|
||||
dssdev->of_ports = BIT(1) | BIT(0);
|
||||
dssdev->bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_SYNC_POSEDGE
|
||||
| DRM_BUS_FLAG_PIXDATA_POSEDGE;
|
||||
|
||||
dssdev->next = omapdss_of_find_connected_device(pdev->dev.of_node, 1);
|
||||
if (IS_ERR(dssdev->next)) {
|
||||
if (PTR_ERR(dssdev->next) != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev, "failed to find video sink\n");
|
||||
return PTR_ERR(dssdev->next);
|
||||
}
|
||||
|
||||
omapdss_device_register(dssdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __exit tfp410_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
|
||||
struct omap_dss_device *dssdev = &ddata->dssdev;
|
||||
|
||||
if (dssdev->next)
|
||||
omapdss_device_put(dssdev->next);
|
||||
omapdss_device_unregister(&ddata->dssdev);
|
||||
|
||||
WARN_ON(omapdss_device_is_enabled(dssdev));
|
||||
if (omapdss_device_is_enabled(dssdev))
|
||||
tfp410_disable(dssdev);
|
||||
|
||||
WARN_ON(omapdss_device_is_connected(dssdev));
|
||||
if (omapdss_device_is_connected(dssdev))
|
||||
omapdss_device_disconnect(NULL, dssdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id tfp410_of_match[] = {
|
||||
{ .compatible = "omapdss,ti,tfp410", },
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, tfp410_of_match);
|
||||
|
||||
static struct platform_driver tfp410_driver = {
|
||||
.probe = tfp410_probe,
|
||||
.remove = __exit_p(tfp410_remove),
|
||||
.driver = {
|
||||
.name = "tfp410",
|
||||
.of_match_table = tfp410_of_match,
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(tfp410_driver);
|
||||
|
||||
MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
|
||||
MODULE_DESCRIPTION("TFP410 DPI to DVI encoder driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -62,35 +62,6 @@ static void tpd_disconnect(struct omap_dss_device *src,
|
|||
omapdss_device_disconnect(dst, dst->next);
|
||||
}
|
||||
|
||||
static int tpd_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_dss_device *src = dssdev->src;
|
||||
int r;
|
||||
|
||||
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
|
||||
return 0;
|
||||
|
||||
r = src->ops->enable(src);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void tpd_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_dss_device *src = dssdev->src;
|
||||
|
||||
if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
|
||||
return;
|
||||
|
||||
src->ops->disable(src);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
|
||||
}
|
||||
|
||||
static bool tpd_detect(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
|
@ -124,8 +95,6 @@ static void tpd_unregister_hpd_cb(struct omap_dss_device *dssdev)
|
|||
static const struct omap_dss_device_ops tpd_ops = {
|
||||
.connect = tpd_connect,
|
||||
.disconnect = tpd_disconnect,
|
||||
.enable = tpd_enable,
|
||||
.disable = tpd_disable,
|
||||
.detect = tpd_detect,
|
||||
.register_hpd_cb = tpd_register_hpd_cb,
|
||||
.unregister_hpd_cb = tpd_unregister_hpd_cb,
|
||||
|
@ -198,7 +167,6 @@ static int tpd_probe(struct platform_device *pdev)
|
|||
dssdev->ops = &tpd_ops;
|
||||
dssdev->dev = &pdev->dev;
|
||||
dssdev->type = OMAP_DISPLAY_TYPE_HDMI;
|
||||
dssdev->output_type = OMAP_DISPLAY_TYPE_HDMI;
|
||||
dssdev->owner = THIS_MODULE;
|
||||
dssdev->of_ports = BIT(1) | BIT(0);
|
||||
dssdev->ops_flags = OMAP_DSS_DEVICE_OP_DETECT
|
||||
|
@ -225,14 +193,6 @@ static int __exit tpd_remove(struct platform_device *pdev)
|
|||
omapdss_device_put(dssdev->next);
|
||||
omapdss_device_unregister(&ddata->dssdev);
|
||||
|
||||
WARN_ON(omapdss_device_is_enabled(dssdev));
|
||||
if (omapdss_device_is_enabled(dssdev))
|
||||
tpd_disable(dssdev);
|
||||
|
||||
WARN_ON(omapdss_device_is_connected(dssdev));
|
||||
if (omapdss_device_is_connected(dssdev))
|
||||
omapdss_device_disconnect(NULL, dssdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,221 +0,0 @@
|
|||
/*
|
||||
* Generic MIPI DPI Panel Driver
|
||||
*
|
||||
* Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
|
||||
* 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/consumer.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/backlight.h>
|
||||
|
||||
#include <video/of_display_timing.h>
|
||||
|
||||
#include "../dss/omapdss.h"
|
||||
|
||||
struct panel_drv_data {
|
||||
struct omap_dss_device dssdev;
|
||||
|
||||
struct videomode vm;
|
||||
|
||||
struct backlight_device *backlight;
|
||||
|
||||
struct gpio_desc *enable_gpio;
|
||||
struct regulator *vcc_supply;
|
||||
};
|
||||
|
||||
#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
|
||||
|
||||
static int panel_dpi_connect(struct omap_dss_device *src,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void panel_dpi_disconnect(struct omap_dss_device *src,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
}
|
||||
|
||||
static int panel_dpi_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *src = dssdev->src;
|
||||
int r;
|
||||
|
||||
if (!omapdss_device_is_connected(dssdev))
|
||||
return -ENODEV;
|
||||
|
||||
if (omapdss_device_is_enabled(dssdev))
|
||||
return 0;
|
||||
|
||||
r = src->ops->enable(src);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
r = regulator_enable(ddata->vcc_supply);
|
||||
if (r) {
|
||||
src->ops->disable(src);
|
||||
return r;
|
||||
}
|
||||
|
||||
gpiod_set_value_cansleep(ddata->enable_gpio, 1);
|
||||
backlight_enable(ddata->backlight);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void panel_dpi_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *src = dssdev->src;
|
||||
|
||||
if (!omapdss_device_is_enabled(dssdev))
|
||||
return;
|
||||
|
||||
backlight_disable(ddata->backlight);
|
||||
|
||||
gpiod_set_value_cansleep(ddata->enable_gpio, 0);
|
||||
regulator_disable(ddata->vcc_supply);
|
||||
|
||||
src->ops->disable(src);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
|
||||
}
|
||||
|
||||
static void panel_dpi_get_timings(struct omap_dss_device *dssdev,
|
||||
struct videomode *vm)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
|
||||
*vm = ddata->vm;
|
||||
}
|
||||
|
||||
static const struct omap_dss_device_ops panel_dpi_ops = {
|
||||
.connect = panel_dpi_connect,
|
||||
.disconnect = panel_dpi_disconnect,
|
||||
|
||||
.enable = panel_dpi_enable,
|
||||
.disable = panel_dpi_disable,
|
||||
|
||||
.get_timings = panel_dpi_get_timings,
|
||||
};
|
||||
|
||||
static int panel_dpi_probe_of(struct platform_device *pdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
int r;
|
||||
struct display_timing timing;
|
||||
struct gpio_desc *gpio;
|
||||
|
||||
gpio = devm_gpiod_get_optional(&pdev->dev, "enable", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(gpio))
|
||||
return PTR_ERR(gpio);
|
||||
|
||||
ddata->enable_gpio = gpio;
|
||||
|
||||
/*
|
||||
* Many different panels are supported by this driver and there are
|
||||
* probably very different needs for their reset pins in regards to
|
||||
* timing and order relative to the enable gpio. So for now it's just
|
||||
* ensured that the reset line isn't active.
|
||||
*/
|
||||
gpio = devm_gpiod_get_optional(&pdev->dev, "reset", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(gpio))
|
||||
return PTR_ERR(gpio);
|
||||
|
||||
ddata->vcc_supply = devm_regulator_get(&pdev->dev, "vcc");
|
||||
if (IS_ERR(ddata->vcc_supply))
|
||||
return PTR_ERR(ddata->vcc_supply);
|
||||
|
||||
ddata->backlight = devm_of_find_backlight(&pdev->dev);
|
||||
|
||||
if (IS_ERR(ddata->backlight))
|
||||
return PTR_ERR(ddata->backlight);
|
||||
|
||||
r = of_get_display_timing(node, "panel-timing", &timing);
|
||||
if (r) {
|
||||
dev_err(&pdev->dev, "failed to get video timing\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
videomode_from_timing(&timing, &ddata->vm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int panel_dpi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct panel_drv_data *ddata;
|
||||
struct omap_dss_device *dssdev;
|
||||
int r;
|
||||
|
||||
ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
|
||||
if (ddata == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, ddata);
|
||||
|
||||
r = panel_dpi_probe_of(pdev);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dssdev = &ddata->dssdev;
|
||||
dssdev->dev = &pdev->dev;
|
||||
dssdev->ops = &panel_dpi_ops;
|
||||
dssdev->type = OMAP_DISPLAY_TYPE_DPI;
|
||||
dssdev->owner = THIS_MODULE;
|
||||
dssdev->of_ports = BIT(0);
|
||||
drm_bus_flags_from_videomode(&ddata->vm, &dssdev->bus_flags);
|
||||
|
||||
omapdss_display_init(dssdev);
|
||||
omapdss_device_register(dssdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __exit panel_dpi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
|
||||
struct omap_dss_device *dssdev = &ddata->dssdev;
|
||||
|
||||
omapdss_device_unregister(dssdev);
|
||||
|
||||
panel_dpi_disable(dssdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id panel_dpi_of_match[] = {
|
||||
{ .compatible = "omapdss,panel-dpi", },
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, panel_dpi_of_match);
|
||||
|
||||
static struct platform_driver panel_dpi_driver = {
|
||||
.probe = panel_dpi_probe,
|
||||
.remove = __exit_p(panel_dpi_remove),
|
||||
.driver = {
|
||||
.name = "panel-dpi",
|
||||
.of_match_table = panel_dpi_of_match,
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(panel_dpi_driver);
|
||||
|
||||
MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
|
||||
MODULE_DESCRIPTION("Generic MIPI DPI Panel Driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -24,6 +24,8 @@
|
|||
#include <linux/of_device.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include <drm/drm_connector.h>
|
||||
|
||||
#include <video/mipi_display.h>
|
||||
#include <video/of_display_timing.h>
|
||||
|
||||
|
@ -41,6 +43,7 @@
|
|||
|
||||
struct panel_drv_data {
|
||||
struct omap_dss_device dssdev;
|
||||
struct omap_dss_device *src;
|
||||
|
||||
struct videomode vm;
|
||||
|
||||
|
@ -141,7 +144,7 @@ static void hw_guard_wait(struct panel_drv_data *ddata)
|
|||
|
||||
static int dsicm_dcs_read_1(struct panel_drv_data *ddata, u8 dcs_cmd, u8 *data)
|
||||
{
|
||||
struct omap_dss_device *src = ddata->dssdev.src;
|
||||
struct omap_dss_device *src = ddata->src;
|
||||
int r;
|
||||
u8 buf[1];
|
||||
|
||||
|
@ -157,14 +160,14 @@ static int dsicm_dcs_read_1(struct panel_drv_data *ddata, u8 dcs_cmd, u8 *data)
|
|||
|
||||
static int dsicm_dcs_write_0(struct panel_drv_data *ddata, u8 dcs_cmd)
|
||||
{
|
||||
struct omap_dss_device *src = ddata->dssdev.src;
|
||||
struct omap_dss_device *src = ddata->src;
|
||||
|
||||
return src->ops->dsi.dcs_write(src, ddata->channel, &dcs_cmd, 1);
|
||||
}
|
||||
|
||||
static int dsicm_dcs_write_1(struct panel_drv_data *ddata, u8 dcs_cmd, u8 param)
|
||||
{
|
||||
struct omap_dss_device *src = ddata->dssdev.src;
|
||||
struct omap_dss_device *src = ddata->src;
|
||||
u8 buf[2] = { dcs_cmd, param };
|
||||
|
||||
return src->ops->dsi.dcs_write(src, ddata->channel, buf, 2);
|
||||
|
@ -173,7 +176,7 @@ static int dsicm_dcs_write_1(struct panel_drv_data *ddata, u8 dcs_cmd, u8 param)
|
|||
static int dsicm_sleep_in(struct panel_drv_data *ddata)
|
||||
|
||||
{
|
||||
struct omap_dss_device *src = ddata->dssdev.src;
|
||||
struct omap_dss_device *src = ddata->src;
|
||||
u8 cmd;
|
||||
int r;
|
||||
|
||||
|
@ -228,7 +231,7 @@ static int dsicm_get_id(struct panel_drv_data *ddata, u8 *id1, u8 *id2, u8 *id3)
|
|||
static int dsicm_set_update_window(struct panel_drv_data *ddata,
|
||||
u16 x, u16 y, u16 w, u16 h)
|
||||
{
|
||||
struct omap_dss_device *src = ddata->dssdev.src;
|
||||
struct omap_dss_device *src = ddata->src;
|
||||
int r;
|
||||
u16 x1 = x;
|
||||
u16 x2 = x + w - 1;
|
||||
|
@ -275,7 +278,7 @@ static void dsicm_cancel_ulps_work(struct panel_drv_data *ddata)
|
|||
|
||||
static int dsicm_enter_ulps(struct panel_drv_data *ddata)
|
||||
{
|
||||
struct omap_dss_device *src = ddata->dssdev.src;
|
||||
struct omap_dss_device *src = ddata->src;
|
||||
int r;
|
||||
|
||||
if (ddata->ulps_enabled)
|
||||
|
@ -309,18 +312,13 @@ err:
|
|||
|
||||
static int dsicm_exit_ulps(struct panel_drv_data *ddata)
|
||||
{
|
||||
struct omap_dss_device *src = ddata->dssdev.src;
|
||||
struct omap_dss_device *src = ddata->src;
|
||||
int r;
|
||||
|
||||
if (!ddata->ulps_enabled)
|
||||
return 0;
|
||||
|
||||
r = src->ops->enable(src);
|
||||
if (r) {
|
||||
dev_err(&ddata->pdev->dev, "failed to enable DSI\n");
|
||||
goto err1;
|
||||
}
|
||||
|
||||
src->ops->enable(src);
|
||||
src->ops->dsi.enable_hs(src, ddata->channel, true);
|
||||
|
||||
r = _dsicm_enable_te(ddata, true);
|
||||
|
@ -347,7 +345,7 @@ err2:
|
|||
enable_irq(gpiod_to_irq(ddata->ext_te_gpio));
|
||||
ddata->ulps_enabled = false;
|
||||
}
|
||||
err1:
|
||||
|
||||
dsicm_queue_ulps_work(ddata);
|
||||
|
||||
return r;
|
||||
|
@ -366,7 +364,7 @@ static int dsicm_wake_up(struct panel_drv_data *ddata)
|
|||
static int dsicm_bl_update_status(struct backlight_device *dev)
|
||||
{
|
||||
struct panel_drv_data *ddata = dev_get_drvdata(&dev->dev);
|
||||
struct omap_dss_device *src = ddata->dssdev.src;
|
||||
struct omap_dss_device *src = ddata->src;
|
||||
int r = 0;
|
||||
int level;
|
||||
|
||||
|
@ -414,7 +412,7 @@ static ssize_t dsicm_num_errors_show(struct device *dev,
|
|||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
|
||||
struct omap_dss_device *src = ddata->dssdev.src;
|
||||
struct omap_dss_device *src = ddata->src;
|
||||
u8 errors = 0;
|
||||
int r;
|
||||
|
||||
|
@ -446,7 +444,7 @@ static ssize_t dsicm_hw_revision_show(struct device *dev,
|
|||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
|
||||
struct omap_dss_device *src = ddata->dssdev.src;
|
||||
struct omap_dss_device *src = ddata->src;
|
||||
u8 id1, id2, id3;
|
||||
int r;
|
||||
|
||||
|
@ -478,7 +476,7 @@ static ssize_t dsicm_store_ulps(struct device *dev,
|
|||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
|
||||
struct omap_dss_device *src = ddata->dssdev.src;
|
||||
struct omap_dss_device *src = ddata->src;
|
||||
unsigned long t;
|
||||
int r;
|
||||
|
||||
|
@ -528,7 +526,7 @@ static ssize_t dsicm_store_ulps_timeout(struct device *dev,
|
|||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
|
||||
struct omap_dss_device *src = ddata->dssdev.src;
|
||||
struct omap_dss_device *src = ddata->src;
|
||||
unsigned long t;
|
||||
int r;
|
||||
|
||||
|
@ -603,7 +601,7 @@ static void dsicm_hw_reset(struct panel_drv_data *ddata)
|
|||
|
||||
static int dsicm_power_on(struct panel_drv_data *ddata)
|
||||
{
|
||||
struct omap_dss_device *src = ddata->dssdev.src;
|
||||
struct omap_dss_device *src = ddata->src;
|
||||
u8 id1, id2, id3;
|
||||
int r;
|
||||
struct omap_dss_dsi_config dsi_config = {
|
||||
|
@ -649,11 +647,7 @@ static int dsicm_power_on(struct panel_drv_data *ddata)
|
|||
goto err_vddi;
|
||||
}
|
||||
|
||||
r = src->ops->enable(src);
|
||||
if (r) {
|
||||
dev_err(&ddata->pdev->dev, "failed to enable DSI\n");
|
||||
goto err_vddi;
|
||||
}
|
||||
src->ops->enable(src);
|
||||
|
||||
dsicm_hw_reset(ddata);
|
||||
|
||||
|
@ -722,7 +716,7 @@ err_vpnl:
|
|||
|
||||
static void dsicm_power_off(struct panel_drv_data *ddata)
|
||||
{
|
||||
struct omap_dss_device *src = ddata->dssdev.src;
|
||||
struct omap_dss_device *src = ddata->src;
|
||||
int r;
|
||||
|
||||
src->ops->dsi.disable_video_output(src, ddata->channel);
|
||||
|
@ -776,6 +770,7 @@ static int dsicm_connect(struct omap_dss_device *src,
|
|||
return r;
|
||||
}
|
||||
|
||||
ddata->src = src;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -785,28 +780,17 @@ static void dsicm_disconnect(struct omap_dss_device *src,
|
|||
struct panel_drv_data *ddata = to_panel_data(dst);
|
||||
|
||||
src->ops->dsi.release_vc(src, ddata->channel);
|
||||
ddata->src = NULL;
|
||||
}
|
||||
|
||||
static int dsicm_enable(struct omap_dss_device *dssdev)
|
||||
static void dsicm_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *src = dssdev->src;
|
||||
struct omap_dss_device *src = ddata->src;
|
||||
int r;
|
||||
|
||||
dev_dbg(&ddata->pdev->dev, "enable\n");
|
||||
|
||||
mutex_lock(&ddata->lock);
|
||||
|
||||
if (!omapdss_device_is_connected(dssdev)) {
|
||||
r = -ENODEV;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (omapdss_device_is_enabled(dssdev)) {
|
||||
r = 0;
|
||||
goto err;
|
||||
}
|
||||
|
||||
src->ops->dsi.bus_lock(src);
|
||||
|
||||
r = dsicm_power_on(ddata);
|
||||
|
@ -816,27 +800,22 @@ static int dsicm_enable(struct omap_dss_device *dssdev)
|
|||
if (r)
|
||||
goto err;
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
|
||||
|
||||
mutex_unlock(&ddata->lock);
|
||||
|
||||
dsicm_bl_power(ddata, true);
|
||||
|
||||
return 0;
|
||||
return;
|
||||
err:
|
||||
dev_dbg(&ddata->pdev->dev, "enable failed\n");
|
||||
dev_dbg(&ddata->pdev->dev, "enable failed (%d)\n", r);
|
||||
mutex_unlock(&ddata->lock);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void dsicm_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *src = dssdev->src;
|
||||
struct omap_dss_device *src = ddata->src;
|
||||
int r;
|
||||
|
||||
dev_dbg(&ddata->pdev->dev, "disable\n");
|
||||
|
||||
dsicm_bl_power(ddata, false);
|
||||
|
||||
mutex_lock(&ddata->lock);
|
||||
|
@ -845,23 +824,19 @@ static void dsicm_disable(struct omap_dss_device *dssdev)
|
|||
|
||||
src->ops->dsi.bus_lock(src);
|
||||
|
||||
if (omapdss_device_is_enabled(dssdev)) {
|
||||
r = dsicm_wake_up(ddata);
|
||||
if (!r)
|
||||
dsicm_power_off(ddata);
|
||||
}
|
||||
r = dsicm_wake_up(ddata);
|
||||
if (!r)
|
||||
dsicm_power_off(ddata);
|
||||
|
||||
src->ops->dsi.bus_unlock(src);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
|
||||
|
||||
mutex_unlock(&ddata->lock);
|
||||
}
|
||||
|
||||
static void dsicm_framedone_cb(int err, void *data)
|
||||
{
|
||||
struct panel_drv_data *ddata = data;
|
||||
struct omap_dss_device *src = ddata->dssdev.src;
|
||||
struct omap_dss_device *src = ddata->src;
|
||||
|
||||
dev_dbg(&ddata->pdev->dev, "framedone, err %d\n", err);
|
||||
src->ops->dsi.bus_unlock(src);
|
||||
|
@ -870,7 +845,7 @@ static void dsicm_framedone_cb(int err, void *data)
|
|||
static irqreturn_t dsicm_te_isr(int irq, void *data)
|
||||
{
|
||||
struct panel_drv_data *ddata = data;
|
||||
struct omap_dss_device *src = ddata->dssdev.src;
|
||||
struct omap_dss_device *src = ddata->src;
|
||||
int old;
|
||||
int r;
|
||||
|
||||
|
@ -896,7 +871,7 @@ static void dsicm_te_timeout_work_callback(struct work_struct *work)
|
|||
{
|
||||
struct panel_drv_data *ddata = container_of(work, struct panel_drv_data,
|
||||
te_timeout_work.work);
|
||||
struct omap_dss_device *src = ddata->dssdev.src;
|
||||
struct omap_dss_device *src = ddata->src;
|
||||
|
||||
dev_err(&ddata->pdev->dev, "TE not received for 250ms!\n");
|
||||
|
||||
|
@ -908,7 +883,7 @@ static int dsicm_update(struct omap_dss_device *dssdev,
|
|||
u16 x, u16 y, u16 w, u16 h)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *src = dssdev->src;
|
||||
struct omap_dss_device *src = ddata->src;
|
||||
int r;
|
||||
|
||||
dev_dbg(&ddata->pdev->dev, "update %d, %d, %d x %d\n", x, y, w, h);
|
||||
|
@ -954,7 +929,7 @@ err:
|
|||
static int dsicm_sync(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *src = dssdev->src;
|
||||
struct omap_dss_device *src = ddata->src;
|
||||
|
||||
dev_dbg(&ddata->pdev->dev, "sync\n");
|
||||
|
||||
|
@ -970,7 +945,7 @@ static int dsicm_sync(struct omap_dss_device *dssdev)
|
|||
|
||||
static int _dsicm_enable_te(struct panel_drv_data *ddata, bool enable)
|
||||
{
|
||||
struct omap_dss_device *src = ddata->dssdev.src;
|
||||
struct omap_dss_device *src = ddata->src;
|
||||
int r;
|
||||
|
||||
if (enable)
|
||||
|
@ -990,7 +965,7 @@ static int _dsicm_enable_te(struct panel_drv_data *ddata, bool enable)
|
|||
static int dsicm_enable_te(struct omap_dss_device *dssdev, bool enable)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *src = dssdev->src;
|
||||
struct omap_dss_device *src = ddata->src;
|
||||
int r;
|
||||
|
||||
mutex_lock(&ddata->lock);
|
||||
|
@ -1041,7 +1016,7 @@ static int dsicm_memory_read(struct omap_dss_device *dssdev,
|
|||
u16 x, u16 y, u16 w, u16 h)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *src = dssdev->src;
|
||||
struct omap_dss_device *src = ddata->src;
|
||||
int r;
|
||||
int first = 1;
|
||||
int plen;
|
||||
|
@ -1123,7 +1098,7 @@ static void dsicm_ulps_work(struct work_struct *work)
|
|||
struct panel_drv_data *ddata = container_of(work, struct panel_drv_data,
|
||||
ulps_work.work);
|
||||
struct omap_dss_device *dssdev = &ddata->dssdev;
|
||||
struct omap_dss_device *src = dssdev->src;
|
||||
struct omap_dss_device *src = ddata->src;
|
||||
|
||||
mutex_lock(&ddata->lock);
|
||||
|
||||
|
@ -1140,29 +1115,32 @@ static void dsicm_ulps_work(struct work_struct *work)
|
|||
mutex_unlock(&ddata->lock);
|
||||
}
|
||||
|
||||
static void dsicm_get_timings(struct omap_dss_device *dssdev,
|
||||
struct videomode *vm)
|
||||
static int dsicm_get_modes(struct omap_dss_device *dssdev,
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
|
||||
*vm = ddata->vm;
|
||||
connector->display_info.width_mm = ddata->width_mm;
|
||||
connector->display_info.height_mm = ddata->height_mm;
|
||||
|
||||
return omapdss_display_get_modes(connector, &ddata->vm);
|
||||
}
|
||||
|
||||
static int dsicm_check_timings(struct omap_dss_device *dssdev,
|
||||
struct videomode *vm)
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
int ret = 0;
|
||||
|
||||
if (vm->hactive != ddata->vm.hactive)
|
||||
if (mode->hdisplay != ddata->vm.hactive)
|
||||
ret = -EINVAL;
|
||||
|
||||
if (vm->vactive != ddata->vm.vactive)
|
||||
if (mode->vdisplay != ddata->vm.vactive)
|
||||
ret = -EINVAL;
|
||||
|
||||
if (ret) {
|
||||
dev_warn(dssdev->dev, "wrong resolution: %d x %d",
|
||||
vm->hactive, vm->vactive);
|
||||
mode->hdisplay, mode->vdisplay);
|
||||
dev_warn(dssdev->dev, "panel resolution: %d x %d",
|
||||
ddata->vm.hactive, ddata->vm.vactive);
|
||||
}
|
||||
|
@ -1170,15 +1148,6 @@ static int dsicm_check_timings(struct omap_dss_device *dssdev,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void dsicm_get_size(struct omap_dss_device *dssdev,
|
||||
unsigned int *width, unsigned int *height)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
|
||||
*width = ddata->width_mm;
|
||||
*height = ddata->height_mm;
|
||||
}
|
||||
|
||||
static const struct omap_dss_device_ops dsicm_ops = {
|
||||
.connect = dsicm_connect,
|
||||
.disconnect = dsicm_disconnect,
|
||||
|
@ -1186,7 +1155,7 @@ static const struct omap_dss_device_ops dsicm_ops = {
|
|||
.enable = dsicm_enable,
|
||||
.disable = dsicm_disable,
|
||||
|
||||
.get_timings = dsicm_get_timings,
|
||||
.get_modes = dsicm_get_modes,
|
||||
.check_timings = dsicm_check_timings,
|
||||
};
|
||||
|
||||
|
@ -1194,8 +1163,6 @@ static const struct omap_dss_driver dsicm_dss_driver = {
|
|||
.update = dsicm_update,
|
||||
.sync = dsicm_sync,
|
||||
|
||||
.get_size = dsicm_get_size,
|
||||
|
||||
.enable_te = dsicm_enable_te,
|
||||
.get_te = dsicm_get_te,
|
||||
|
||||
|
@ -1305,8 +1272,10 @@ static int dsicm_probe(struct platform_device *pdev)
|
|||
dssdev->ops = &dsicm_ops;
|
||||
dssdev->driver = &dsicm_dss_driver;
|
||||
dssdev->type = OMAP_DISPLAY_TYPE_DSI;
|
||||
dssdev->display = true;
|
||||
dssdev->owner = THIS_MODULE;
|
||||
dssdev->of_ports = BIT(0);
|
||||
dssdev->ops_flags = OMAP_DSS_DEVICE_OP_MODES;
|
||||
|
||||
dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE |
|
||||
OMAP_DSS_DISPLAY_CAP_TEAR_ELIM;
|
||||
|
@ -1385,8 +1354,9 @@ static int __exit dsicm_remove(struct platform_device *pdev)
|
|||
|
||||
omapdss_device_unregister(dssdev);
|
||||
|
||||
dsicm_disable(dssdev);
|
||||
omapdss_device_disconnect(dssdev->src, dssdev);
|
||||
if (omapdss_device_is_enabled(dssdev))
|
||||
dsicm_disable(dssdev);
|
||||
omapdss_device_disconnect(ddata->src, dssdev);
|
||||
|
||||
sysfs_remove_group(&pdev->dev.kobj, &dsicm_attr_group);
|
||||
|
||||
|
|
|
@ -123,52 +123,28 @@ static void lb035q02_disconnect(struct omap_dss_device *src,
|
|||
{
|
||||
}
|
||||
|
||||
static int lb035q02_enable(struct omap_dss_device *dssdev)
|
||||
static void lb035q02_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *src = dssdev->src;
|
||||
int r;
|
||||
|
||||
if (!omapdss_device_is_connected(dssdev))
|
||||
return -ENODEV;
|
||||
|
||||
if (omapdss_device_is_enabled(dssdev))
|
||||
return 0;
|
||||
|
||||
r = src->ops->enable(src);
|
||||
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 lb035q02_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *src = dssdev->src;
|
||||
|
||||
if (!omapdss_device_is_enabled(dssdev))
|
||||
return;
|
||||
|
||||
if (ddata->enable_gpio)
|
||||
gpiod_set_value_cansleep(ddata->enable_gpio, 0);
|
||||
|
||||
src->ops->disable(src);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
|
||||
}
|
||||
|
||||
static void lb035q02_get_timings(struct omap_dss_device *dssdev,
|
||||
struct videomode *vm)
|
||||
static int lb035q02_get_modes(struct omap_dss_device *dssdev,
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
|
||||
*vm = ddata->vm;
|
||||
return omapdss_display_get_modes(connector, &ddata->vm);
|
||||
}
|
||||
|
||||
static const struct omap_dss_device_ops lb035q02_ops = {
|
||||
|
@ -178,7 +154,7 @@ static const struct omap_dss_device_ops lb035q02_ops = {
|
|||
.enable = lb035q02_enable,
|
||||
.disable = lb035q02_disable,
|
||||
|
||||
.get_timings = lb035q02_get_timings,
|
||||
.get_modes = lb035q02_get_modes,
|
||||
};
|
||||
|
||||
static int lb035q02_probe_of(struct spi_device *spi)
|
||||
|
@ -221,16 +197,19 @@ static int lb035q02_panel_spi_probe(struct spi_device *spi)
|
|||
dssdev->dev = &spi->dev;
|
||||
dssdev->ops = &lb035q02_ops;
|
||||
dssdev->type = OMAP_DISPLAY_TYPE_DPI;
|
||||
dssdev->display = true;
|
||||
dssdev->owner = THIS_MODULE;
|
||||
dssdev->of_ports = BIT(0);
|
||||
dssdev->ops_flags = OMAP_DSS_DEVICE_OP_MODES;
|
||||
|
||||
/*
|
||||
* Note: According to the panel documentation:
|
||||
* DE is active LOW
|
||||
* DATA needs to be driven on the FALLING edge
|
||||
*/
|
||||
dssdev->bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_SYNC_NEGEDGE
|
||||
| DRM_BUS_FLAG_PIXDATA_POSEDGE;
|
||||
dssdev->bus_flags = DRM_BUS_FLAG_DE_HIGH
|
||||
| DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE
|
||||
| DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE;
|
||||
|
||||
omapdss_display_init(dssdev);
|
||||
omapdss_device_register(dssdev);
|
||||
|
|
|
@ -118,50 +118,26 @@ static void nec_8048_disconnect(struct omap_dss_device *src,
|
|||
{
|
||||
}
|
||||
|
||||
static int nec_8048_enable(struct omap_dss_device *dssdev)
|
||||
static void nec_8048_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *src = dssdev->src;
|
||||
int r;
|
||||
|
||||
if (!omapdss_device_is_connected(dssdev))
|
||||
return -ENODEV;
|
||||
|
||||
if (omapdss_device_is_enabled(dssdev))
|
||||
return 0;
|
||||
|
||||
r = src->ops->enable(src);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
gpiod_set_value_cansleep(ddata->res_gpio, 1);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nec_8048_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *src = dssdev->src;
|
||||
|
||||
if (!omapdss_device_is_enabled(dssdev))
|
||||
return;
|
||||
|
||||
gpiod_set_value_cansleep(ddata->res_gpio, 0);
|
||||
|
||||
src->ops->disable(src);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
|
||||
}
|
||||
|
||||
static void nec_8048_get_timings(struct omap_dss_device *dssdev,
|
||||
struct videomode *vm)
|
||||
static int nec_8048_get_modes(struct omap_dss_device *dssdev,
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
|
||||
*vm = ddata->vm;
|
||||
return omapdss_display_get_modes(connector, &ddata->vm);
|
||||
}
|
||||
|
||||
static const struct omap_dss_device_ops nec_8048_ops = {
|
||||
|
@ -171,7 +147,7 @@ static const struct omap_dss_device_ops nec_8048_ops = {
|
|||
.enable = nec_8048_enable,
|
||||
.disable = nec_8048_disable,
|
||||
|
||||
.get_timings = nec_8048_get_timings,
|
||||
.get_modes = nec_8048_get_modes,
|
||||
};
|
||||
|
||||
static int nec_8048_probe(struct spi_device *spi)
|
||||
|
@ -216,10 +192,13 @@ static int nec_8048_probe(struct spi_device *spi)
|
|||
dssdev->dev = &spi->dev;
|
||||
dssdev->ops = &nec_8048_ops;
|
||||
dssdev->type = OMAP_DISPLAY_TYPE_DPI;
|
||||
dssdev->display = true;
|
||||
dssdev->owner = THIS_MODULE;
|
||||
dssdev->of_ports = BIT(0);
|
||||
dssdev->bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_SYNC_POSEDGE
|
||||
| DRM_BUS_FLAG_PIXDATA_POSEDGE;
|
||||
dssdev->ops_flags = OMAP_DSS_DEVICE_OP_MODES;
|
||||
dssdev->bus_flags = DRM_BUS_FLAG_DE_HIGH
|
||||
| DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE
|
||||
| DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE;
|
||||
|
||||
omapdss_display_init(dssdev);
|
||||
omapdss_device_register(dssdev);
|
||||
|
|
|
@ -62,29 +62,22 @@ static void sharp_ls_disconnect(struct omap_dss_device *src,
|
|||
{
|
||||
}
|
||||
|
||||
static int sharp_ls_enable(struct omap_dss_device *dssdev)
|
||||
static void sharp_ls_pre_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *src = dssdev->src;
|
||||
int r;
|
||||
|
||||
if (!omapdss_device_is_connected(dssdev))
|
||||
return -ENODEV;
|
||||
|
||||
if (omapdss_device_is_enabled(dssdev))
|
||||
return 0;
|
||||
|
||||
if (ddata->vcc) {
|
||||
r = regulator_enable(ddata->vcc);
|
||||
if (r != 0)
|
||||
return r;
|
||||
if (r)
|
||||
dev_err(dssdev->dev, "%s: failed to enable regulator\n",
|
||||
__func__);
|
||||
}
|
||||
}
|
||||
|
||||
r = src->ops->enable(src);
|
||||
if (r) {
|
||||
regulator_disable(ddata->vcc);
|
||||
return r;
|
||||
}
|
||||
static void sharp_ls_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
|
||||
/* wait couple of vsyncs until enabling the LCD */
|
||||
msleep(50);
|
||||
|
@ -94,19 +87,11 @@ static int sharp_ls_enable(struct omap_dss_device *dssdev)
|
|||
|
||||
if (ddata->ini_gpio)
|
||||
gpiod_set_value_cansleep(ddata->ini_gpio, 1);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sharp_ls_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *src = dssdev->src;
|
||||
|
||||
if (!omapdss_device_is_enabled(dssdev))
|
||||
return;
|
||||
|
||||
if (ddata->ini_gpio)
|
||||
gpiod_set_value_cansleep(ddata->ini_gpio, 0);
|
||||
|
@ -115,33 +100,35 @@ static void sharp_ls_disable(struct omap_dss_device *dssdev)
|
|||
gpiod_set_value_cansleep(ddata->resb_gpio, 0);
|
||||
|
||||
/* wait at least 5 vsyncs after disabling the LCD */
|
||||
|
||||
msleep(100);
|
||||
|
||||
src->ops->disable(src);
|
||||
|
||||
if (ddata->vcc)
|
||||
regulator_disable(ddata->vcc);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
|
||||
}
|
||||
|
||||
static void sharp_ls_get_timings(struct omap_dss_device *dssdev,
|
||||
struct videomode *vm)
|
||||
static void sharp_ls_post_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
|
||||
*vm = ddata->vm;
|
||||
if (ddata->vcc)
|
||||
regulator_disable(ddata->vcc);
|
||||
}
|
||||
|
||||
static int sharp_ls_get_modes(struct omap_dss_device *dssdev,
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
|
||||
return omapdss_display_get_modes(connector, &ddata->vm);
|
||||
}
|
||||
|
||||
static const struct omap_dss_device_ops sharp_ls_ops = {
|
||||
.connect = sharp_ls_connect,
|
||||
.disconnect = sharp_ls_disconnect,
|
||||
|
||||
.pre_enable = sharp_ls_pre_enable,
|
||||
.enable = sharp_ls_enable,
|
||||
.disable = sharp_ls_disable,
|
||||
.post_disable = sharp_ls_post_disable,
|
||||
|
||||
.get_timings = sharp_ls_get_timings,
|
||||
.get_modes = sharp_ls_get_modes,
|
||||
};
|
||||
|
||||
static int sharp_ls_get_gpio_of(struct device *dev, int index, int val,
|
||||
|
@ -220,15 +207,18 @@ static int sharp_ls_probe(struct platform_device *pdev)
|
|||
dssdev->dev = &pdev->dev;
|
||||
dssdev->ops = &sharp_ls_ops;
|
||||
dssdev->type = OMAP_DISPLAY_TYPE_DPI;
|
||||
dssdev->display = true;
|
||||
dssdev->owner = THIS_MODULE;
|
||||
dssdev->of_ports = BIT(0);
|
||||
dssdev->ops_flags = OMAP_DSS_DEVICE_OP_MODES;
|
||||
|
||||
/*
|
||||
* Note: According to the panel documentation:
|
||||
* DATA needs to be driven on the FALLING edge
|
||||
*/
|
||||
dssdev->bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_SYNC_NEGEDGE
|
||||
| DRM_BUS_FLAG_PIXDATA_POSEDGE;
|
||||
dssdev->bus_flags = DRM_BUS_FLAG_DE_HIGH
|
||||
| DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE
|
||||
| DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE;
|
||||
|
||||
omapdss_display_init(dssdev);
|
||||
omapdss_device_register(dssdev);
|
||||
|
@ -243,7 +233,10 @@ static int __exit sharp_ls_remove(struct platform_device *pdev)
|
|||
|
||||
omapdss_device_unregister(dssdev);
|
||||
|
||||
sharp_ls_disable(dssdev);
|
||||
if (omapdss_device_is_enabled(dssdev)) {
|
||||
sharp_ls_disable(dssdev);
|
||||
sharp_ls_post_disable(dssdev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -516,17 +516,9 @@ static void acx565akm_disconnect(struct omap_dss_device *src,
|
|||
static int acx565akm_panel_power_on(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *src = dssdev->src;
|
||||
int r;
|
||||
|
||||
dev_dbg(&ddata->spi->dev, "%s\n", __func__);
|
||||
|
||||
r = src->ops->enable(src);
|
||||
if (r) {
|
||||
pr_err("%s sdi enable failed\n", __func__);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*FIXME tweak me */
|
||||
msleep(50);
|
||||
|
||||
|
@ -562,7 +554,6 @@ static int acx565akm_panel_power_on(struct omap_dss_device *dssdev)
|
|||
static void acx565akm_panel_power_off(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *src = dssdev->src;
|
||||
|
||||
dev_dbg(dssdev->dev, "%s\n", __func__);
|
||||
|
||||
|
@ -585,56 +576,32 @@ static void acx565akm_panel_power_off(struct omap_dss_device *dssdev)
|
|||
|
||||
/* FIXME need to tweak this delay */
|
||||
msleep(100);
|
||||
|
||||
src->ops->disable(src);
|
||||
}
|
||||
|
||||
static int acx565akm_enable(struct omap_dss_device *dssdev)
|
||||
static void acx565akm_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
int r;
|
||||
|
||||
dev_dbg(dssdev->dev, "%s\n", __func__);
|
||||
|
||||
if (!omapdss_device_is_connected(dssdev))
|
||||
return -ENODEV;
|
||||
|
||||
if (omapdss_device_is_enabled(dssdev))
|
||||
return 0;
|
||||
|
||||
mutex_lock(&ddata->mutex);
|
||||
r = acx565akm_panel_power_on(dssdev);
|
||||
acx565akm_panel_power_on(dssdev);
|
||||
mutex_unlock(&ddata->mutex);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void acx565akm_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
|
||||
dev_dbg(dssdev->dev, "%s\n", __func__);
|
||||
|
||||
if (!omapdss_device_is_enabled(dssdev))
|
||||
return;
|
||||
|
||||
mutex_lock(&ddata->mutex);
|
||||
acx565akm_panel_power_off(dssdev);
|
||||
mutex_unlock(&ddata->mutex);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
|
||||
}
|
||||
|
||||
static void acx565akm_get_timings(struct omap_dss_device *dssdev,
|
||||
struct videomode *vm)
|
||||
static int acx565akm_get_modes(struct omap_dss_device *dssdev,
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
|
||||
*vm = ddata->vm;
|
||||
return omapdss_display_get_modes(connector, &ddata->vm);
|
||||
}
|
||||
|
||||
static const struct omap_dss_device_ops acx565akm_ops = {
|
||||
|
@ -644,7 +611,7 @@ static const struct omap_dss_device_ops acx565akm_ops = {
|
|||
.enable = acx565akm_enable,
|
||||
.disable = acx565akm_disable,
|
||||
|
||||
.get_timings = acx565akm_get_timings,
|
||||
.get_modes = acx565akm_get_modes,
|
||||
};
|
||||
|
||||
static int acx565akm_probe(struct spi_device *spi)
|
||||
|
@ -739,10 +706,13 @@ static int acx565akm_probe(struct spi_device *spi)
|
|||
dssdev->dev = &spi->dev;
|
||||
dssdev->ops = &acx565akm_ops;
|
||||
dssdev->type = OMAP_DISPLAY_TYPE_SDI;
|
||||
dssdev->display = true;
|
||||
dssdev->owner = THIS_MODULE;
|
||||
dssdev->of_ports = BIT(0);
|
||||
dssdev->bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_SYNC_NEGEDGE
|
||||
| DRM_BUS_FLAG_PIXDATA_POSEDGE;
|
||||
dssdev->ops_flags = OMAP_DSS_DEVICE_OP_MODES;
|
||||
dssdev->bus_flags = DRM_BUS_FLAG_DE_HIGH
|
||||
| DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE
|
||||
| DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE;
|
||||
|
||||
omapdss_display_init(dssdev);
|
||||
omapdss_device_register(dssdev);
|
||||
|
@ -766,7 +736,8 @@ static int acx565akm_remove(struct spi_device *spi)
|
|||
|
||||
omapdss_device_unregister(dssdev);
|
||||
|
||||
acx565akm_disable(dssdev);
|
||||
if (omapdss_device_is_enabled(dssdev))
|
||||
acx565akm_disable(dssdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -35,6 +35,8 @@ struct panel_drv_data {
|
|||
|
||||
struct videomode vm;
|
||||
|
||||
struct backlight_device *backlight;
|
||||
|
||||
struct spi_device *spi_dev;
|
||||
};
|
||||
|
||||
|
@ -169,24 +171,12 @@ static void td028ttec1_panel_disconnect(struct omap_dss_device *src,
|
|||
{
|
||||
}
|
||||
|
||||
static int td028ttec1_panel_enable(struct omap_dss_device *dssdev)
|
||||
static void td028ttec1_panel_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *src = dssdev->src;
|
||||
int r;
|
||||
int r = 0;
|
||||
|
||||
if (!omapdss_device_is_connected(dssdev))
|
||||
return -ENODEV;
|
||||
|
||||
if (omapdss_device_is_enabled(dssdev))
|
||||
return 0;
|
||||
|
||||
r = src->ops->enable(src);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dev_dbg(dssdev->dev, "td028ttec1_panel_enable() - state %d\n",
|
||||
dssdev->state);
|
||||
dev_dbg(dssdev->dev, "%s: state %d\n", __func__, dssdev->state);
|
||||
|
||||
/* three times command zero */
|
||||
r |= jbt_ret_write_0(ddata, 0x00);
|
||||
|
@ -197,8 +187,8 @@ static int td028ttec1_panel_enable(struct omap_dss_device *dssdev)
|
|||
usleep_range(1000, 2000);
|
||||
|
||||
if (r) {
|
||||
dev_warn(dssdev->dev, "transfer error\n");
|
||||
goto transfer_err;
|
||||
dev_warn(dssdev->dev, "%s: transfer error\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
/* deep standby out */
|
||||
|
@ -268,20 +258,17 @@ static int td028ttec1_panel_enable(struct omap_dss_device *dssdev)
|
|||
|
||||
r |= jbt_ret_write_0(ddata, JBT_REG_DISPLAY_ON);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
|
||||
if (r)
|
||||
dev_err(dssdev->dev, "%s: write error\n", __func__);
|
||||
|
||||
transfer_err:
|
||||
|
||||
return r ? -EIO : 0;
|
||||
backlight_enable(ddata->backlight);
|
||||
}
|
||||
|
||||
static void td028ttec1_panel_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *src = dssdev->src;
|
||||
|
||||
if (!omapdss_device_is_enabled(dssdev))
|
||||
return;
|
||||
backlight_disable(ddata->backlight);
|
||||
|
||||
dev_dbg(dssdev->dev, "td028ttec1_panel_disable()\n");
|
||||
|
||||
|
@ -289,18 +276,14 @@ static void td028ttec1_panel_disable(struct omap_dss_device *dssdev)
|
|||
jbt_reg_write_2(ddata, JBT_REG_OUTPUT_CONTROL, 0x8002);
|
||||
jbt_ret_write_0(ddata, JBT_REG_SLEEP_IN);
|
||||
jbt_reg_write_1(ddata, JBT_REG_POWER_ON_OFF, 0x00);
|
||||
|
||||
src->ops->disable(src);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
|
||||
}
|
||||
|
||||
static void td028ttec1_panel_get_timings(struct omap_dss_device *dssdev,
|
||||
struct videomode *vm)
|
||||
static int td028ttec1_panel_get_modes(struct omap_dss_device *dssdev,
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
|
||||
*vm = ddata->vm;
|
||||
return omapdss_display_get_modes(connector, &ddata->vm);
|
||||
}
|
||||
|
||||
static const struct omap_dss_device_ops td028ttec1_ops = {
|
||||
|
@ -310,7 +293,7 @@ static const struct omap_dss_device_ops td028ttec1_ops = {
|
|||
.enable = td028ttec1_panel_enable,
|
||||
.disable = td028ttec1_panel_disable,
|
||||
|
||||
.get_timings = td028ttec1_panel_get_timings,
|
||||
.get_modes = td028ttec1_panel_get_modes,
|
||||
};
|
||||
|
||||
static int td028ttec1_panel_probe(struct spi_device *spi)
|
||||
|
@ -334,6 +317,10 @@ static int td028ttec1_panel_probe(struct spi_device *spi)
|
|||
if (ddata == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
ddata->backlight = devm_of_find_backlight(&spi->dev);
|
||||
if (IS_ERR(ddata->backlight))
|
||||
return PTR_ERR(ddata->backlight);
|
||||
|
||||
dev_set_drvdata(&spi->dev, ddata);
|
||||
|
||||
ddata->spi_dev = spi;
|
||||
|
@ -344,15 +331,18 @@ static int td028ttec1_panel_probe(struct spi_device *spi)
|
|||
dssdev->dev = &spi->dev;
|
||||
dssdev->ops = &td028ttec1_ops;
|
||||
dssdev->type = OMAP_DISPLAY_TYPE_DPI;
|
||||
dssdev->display = true;
|
||||
dssdev->owner = THIS_MODULE;
|
||||
dssdev->of_ports = BIT(0);
|
||||
dssdev->ops_flags = OMAP_DSS_DEVICE_OP_MODES;
|
||||
|
||||
/*
|
||||
* Note: According to the panel documentation:
|
||||
* SYNC needs to be driven on the FALLING edge
|
||||
*/
|
||||
dssdev->bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_SYNC_POSEDGE
|
||||
| DRM_BUS_FLAG_PIXDATA_NEGEDGE;
|
||||
dssdev->bus_flags = DRM_BUS_FLAG_DE_HIGH
|
||||
| DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE
|
||||
| DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE;
|
||||
|
||||
omapdss_display_init(dssdev);
|
||||
omapdss_device_register(dssdev);
|
||||
|
|
|
@ -320,22 +320,11 @@ static void tpo_td043_disconnect(struct omap_dss_device *src,
|
|||
{
|
||||
}
|
||||
|
||||
static int tpo_td043_enable(struct omap_dss_device *dssdev)
|
||||
static void tpo_td043_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *src = dssdev->src;
|
||||
int r;
|
||||
|
||||
if (!omapdss_device_is_connected(dssdev))
|
||||
return -ENODEV;
|
||||
|
||||
if (omapdss_device_is_enabled(dssdev))
|
||||
return 0;
|
||||
|
||||
r = src->ops->enable(src);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
/*
|
||||
* If we are resuming from system suspend, SPI clocks might not be
|
||||
* enabled yet, so we'll program the LCD from SPI PM resume callback.
|
||||
|
@ -343,38 +332,27 @@ static int tpo_td043_enable(struct omap_dss_device *dssdev)
|
|||
if (!ddata->spi_suspended) {
|
||||
r = tpo_td043_power_on(ddata);
|
||||
if (r) {
|
||||
src->ops->disable(src);
|
||||
return r;
|
||||
dev_err(&ddata->spi->dev, "%s: power on failed (%d)\n",
|
||||
__func__, r);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tpo_td043_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
struct omap_dss_device *src = dssdev->src;
|
||||
|
||||
if (!omapdss_device_is_enabled(dssdev))
|
||||
return;
|
||||
|
||||
src->ops->disable(src);
|
||||
|
||||
if (!ddata->spi_suspended)
|
||||
tpo_td043_power_off(ddata);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
|
||||
}
|
||||
|
||||
static void tpo_td043_get_timings(struct omap_dss_device *dssdev,
|
||||
struct videomode *vm)
|
||||
static int tpo_td043_get_modes(struct omap_dss_device *dssdev,
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
struct panel_drv_data *ddata = to_panel_data(dssdev);
|
||||
|
||||
*vm = ddata->vm;
|
||||
return omapdss_display_get_modes(connector, &ddata->vm);
|
||||
}
|
||||
|
||||
static const struct omap_dss_device_ops tpo_td043_ops = {
|
||||
|
@ -384,7 +362,7 @@ static const struct omap_dss_device_ops tpo_td043_ops = {
|
|||
.enable = tpo_td043_enable,
|
||||
.disable = tpo_td043_disable,
|
||||
|
||||
.get_timings = tpo_td043_get_timings,
|
||||
.get_modes = tpo_td043_get_modes,
|
||||
};
|
||||
|
||||
static int tpo_td043_probe(struct spi_device *spi)
|
||||
|
@ -442,15 +420,18 @@ static int tpo_td043_probe(struct spi_device *spi)
|
|||
dssdev->dev = &spi->dev;
|
||||
dssdev->ops = &tpo_td043_ops;
|
||||
dssdev->type = OMAP_DISPLAY_TYPE_DPI;
|
||||
dssdev->display = true;
|
||||
dssdev->owner = THIS_MODULE;
|
||||
dssdev->of_ports = BIT(0);
|
||||
dssdev->ops_flags = OMAP_DSS_DEVICE_OP_MODES;
|
||||
|
||||
/*
|
||||
* Note: According to the panel documentation:
|
||||
* SYNC needs to be driven on the FALLING edge
|
||||
*/
|
||||
dssdev->bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_SYNC_POSEDGE
|
||||
| DRM_BUS_FLAG_PIXDATA_NEGEDGE;
|
||||
dssdev->bus_flags = DRM_BUS_FLAG_DE_HIGH
|
||||
| DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE
|
||||
| DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE;
|
||||
|
||||
omapdss_display_init(dssdev);
|
||||
omapdss_device_register(dssdev);
|
||||
|
@ -467,7 +448,8 @@ static int tpo_td043_remove(struct spi_device *spi)
|
|||
|
||||
omapdss_device_unregister(dssdev);
|
||||
|
||||
tpo_td043_disable(dssdev);
|
||||
if (omapdss_device_is_enabled(dssdev))
|
||||
tpo_td043_disable(dssdev);
|
||||
|
||||
sysfs_remove_group(&spi->dev.kobj, &tpo_td043_attr_group);
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "dss.h"
|
||||
#include "omapdss.h"
|
||||
|
@ -112,13 +113,12 @@ void omapdss_device_put(struct omap_dss_device *dssdev)
|
|||
}
|
||||
EXPORT_SYMBOL(omapdss_device_put);
|
||||
|
||||
struct omap_dss_device *omapdss_find_device_by_port(struct device_node *src,
|
||||
unsigned int port)
|
||||
struct omap_dss_device *omapdss_find_device_by_node(struct device_node *node)
|
||||
{
|
||||
struct omap_dss_device *dssdev;
|
||||
|
||||
list_for_each_entry(dssdev, &omapdss_devices_list, list) {
|
||||
if (dssdev->dev->of_node == src && dssdev->of_ports & BIT(port))
|
||||
if (dssdev->dev->of_node == node)
|
||||
return omapdss_device_get(dssdev);
|
||||
}
|
||||
|
||||
|
@ -126,13 +126,10 @@ struct omap_dss_device *omapdss_find_device_by_port(struct device_node *src,
|
|||
}
|
||||
|
||||
/*
|
||||
* Search for the next device starting at @from. The type argument specfies
|
||||
* which device types to consider when searching. Searching for multiple types
|
||||
* is supported by and'ing their type flags. Release the reference to the @from
|
||||
* device, and acquire a reference to the returned device if found.
|
||||
* Search for the next output device starting at @from. Release the reference to
|
||||
* the @from device, and acquire a reference to the returned device if found.
|
||||
*/
|
||||
struct omap_dss_device *omapdss_device_get_next(struct omap_dss_device *from,
|
||||
enum omap_dss_device_type type)
|
||||
struct omap_dss_device *omapdss_device_next_output(struct omap_dss_device *from)
|
||||
{
|
||||
struct omap_dss_device *dssdev;
|
||||
struct list_head *list;
|
||||
|
@ -160,15 +157,8 @@ struct omap_dss_device *omapdss_device_get_next(struct omap_dss_device *from,
|
|||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Accept display entities if the display type is requested,
|
||||
* and output entities if the output type is requested.
|
||||
*/
|
||||
if ((type & OMAP_DSS_DEVICE_TYPE_DISPLAY) &&
|
||||
!dssdev->output_type)
|
||||
goto done;
|
||||
if ((type & OMAP_DSS_DEVICE_TYPE_OUTPUT) && dssdev->id &&
|
||||
dssdev->next)
|
||||
if (dssdev->id &&
|
||||
(dssdev->next || dssdev->bridge || dssdev->panel))
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
@ -183,7 +173,12 @@ done:
|
|||
mutex_unlock(&omapdss_devices_lock);
|
||||
return dssdev;
|
||||
}
|
||||
EXPORT_SYMBOL(omapdss_device_get_next);
|
||||
EXPORT_SYMBOL(omapdss_device_next_output);
|
||||
|
||||
static bool omapdss_device_is_connected(struct omap_dss_device *dssdev)
|
||||
{
|
||||
return dssdev->dss;
|
||||
}
|
||||
|
||||
int omapdss_device_connect(struct dss_device *dss,
|
||||
struct omap_dss_device *src,
|
||||
|
@ -191,7 +186,19 @@ int omapdss_device_connect(struct dss_device *dss,
|
|||
{
|
||||
int ret;
|
||||
|
||||
dev_dbg(dst->dev, "connect\n");
|
||||
dev_dbg(&dss->pdev->dev, "connect(%s, %s)\n",
|
||||
src ? dev_name(src->dev) : "NULL",
|
||||
dst ? dev_name(dst->dev) : "NULL");
|
||||
|
||||
if (!dst) {
|
||||
/*
|
||||
* The destination is NULL when the source is connected to a
|
||||
* bridge or panel instead of a DSS device. Stop here, we will
|
||||
* attach the bridge or panel later when we will have a DRM
|
||||
* encoder.
|
||||
*/
|
||||
return src && (src->bridge || src->panel) ? 0 : -EINVAL;
|
||||
}
|
||||
|
||||
if (omapdss_device_is_connected(dst))
|
||||
return -EBUSY;
|
||||
|
@ -204,12 +211,6 @@ int omapdss_device_connect(struct dss_device *dss,
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (src) {
|
||||
WARN_ON(src->dst);
|
||||
dst->src = src;
|
||||
src->dst = dst;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omapdss_device_connect);
|
||||
|
@ -217,19 +218,20 @@ EXPORT_SYMBOL_GPL(omapdss_device_connect);
|
|||
void omapdss_device_disconnect(struct omap_dss_device *src,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
dev_dbg(dst->dev, "disconnect\n");
|
||||
struct dss_device *dss = src ? src->dss : dst->dss;
|
||||
|
||||
if (!dst->id && !omapdss_device_is_connected(dst)) {
|
||||
WARN_ON(dst->output_type);
|
||||
dev_dbg(&dss->pdev->dev, "disconnect(%s, %s)\n",
|
||||
src ? dev_name(src->dev) : "NULL",
|
||||
dst ? dev_name(dst->dev) : "NULL");
|
||||
|
||||
if (!dst) {
|
||||
WARN_ON(!src->bridge && !src->panel);
|
||||
return;
|
||||
}
|
||||
|
||||
if (src) {
|
||||
if (WARN_ON(dst != src->dst))
|
||||
return;
|
||||
|
||||
dst->src = NULL;
|
||||
src->dst = NULL;
|
||||
if (!dst->id && !omapdss_device_is_connected(dst)) {
|
||||
WARN_ON(!dst->display);
|
||||
return;
|
||||
}
|
||||
|
||||
WARN_ON(dst->state != OMAP_DSS_DISPLAY_DISABLED);
|
||||
|
@ -239,6 +241,58 @@ void omapdss_device_disconnect(struct omap_dss_device *src,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(omapdss_device_disconnect);
|
||||
|
||||
void omapdss_device_pre_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
if (!dssdev)
|
||||
return;
|
||||
|
||||
omapdss_device_pre_enable(dssdev->next);
|
||||
|
||||
if (dssdev->ops->pre_enable)
|
||||
dssdev->ops->pre_enable(dssdev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omapdss_device_pre_enable);
|
||||
|
||||
void omapdss_device_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
if (!dssdev)
|
||||
return;
|
||||
|
||||
if (dssdev->ops->enable)
|
||||
dssdev->ops->enable(dssdev);
|
||||
|
||||
omapdss_device_enable(dssdev->next);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omapdss_device_enable);
|
||||
|
||||
void omapdss_device_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
if (!dssdev)
|
||||
return;
|
||||
|
||||
omapdss_device_disable(dssdev->next);
|
||||
|
||||
if (dssdev->ops->disable)
|
||||
dssdev->ops->disable(dssdev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omapdss_device_disable);
|
||||
|
||||
void omapdss_device_post_disable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
if (!dssdev)
|
||||
return;
|
||||
|
||||
if (dssdev->ops->post_disable)
|
||||
dssdev->ops->post_disable(dssdev);
|
||||
|
||||
omapdss_device_post_disable(dssdev->next);
|
||||
|
||||
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omapdss_device_post_disable);
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Components Handling
|
||||
*/
|
||||
|
@ -249,6 +303,7 @@ struct omapdss_comp_node {
|
|||
struct list_head list;
|
||||
struct device_node *node;
|
||||
bool dss_core_component;
|
||||
const char *compat;
|
||||
};
|
||||
|
||||
static bool omapdss_list_contains(const struct device_node *node)
|
||||
|
@ -266,13 +321,20 @@ static bool omapdss_list_contains(const struct device_node *node)
|
|||
static void omapdss_walk_device(struct device *dev, struct device_node *node,
|
||||
bool dss_core)
|
||||
{
|
||||
struct omapdss_comp_node *comp;
|
||||
struct device_node *n;
|
||||
struct omapdss_comp_node *comp = devm_kzalloc(dev, sizeof(*comp),
|
||||
GFP_KERNEL);
|
||||
const char *compat;
|
||||
int ret;
|
||||
|
||||
ret = of_property_read_string(node, "compatible", &compat);
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
comp = devm_kzalloc(dev, sizeof(*comp), GFP_KERNEL);
|
||||
if (comp) {
|
||||
comp->node = node;
|
||||
comp->dss_core_component = dss_core;
|
||||
comp->compat = compat;
|
||||
list_add(&comp->list, &omapdss_comp_list);
|
||||
}
|
||||
|
||||
|
@ -312,12 +374,8 @@ void omapdss_gather_components(struct device *dev)
|
|||
|
||||
omapdss_walk_device(dev, dev->of_node, true);
|
||||
|
||||
for_each_available_child_of_node(dev->of_node, child) {
|
||||
if (!of_find_property(child, "compatible", NULL))
|
||||
continue;
|
||||
|
||||
for_each_available_child_of_node(dev->of_node, child)
|
||||
omapdss_walk_device(dev, child, true);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(omapdss_gather_components);
|
||||
|
||||
|
@ -325,6 +383,8 @@ static bool omapdss_component_is_loaded(struct omapdss_comp_node *comp)
|
|||
{
|
||||
if (comp->dss_core_component)
|
||||
return true;
|
||||
if (!strstarts(comp->compat, "omapdss,"))
|
||||
return true;
|
||||
if (omapdss_device_is_registered(comp->node))
|
||||
return true;
|
||||
|
||||
|
|
|
@ -23,6 +23,9 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include <drm/drm_connector.h>
|
||||
#include <drm/drm_modes.h>
|
||||
|
||||
#include "omapdss.h"
|
||||
|
||||
static int disp_num_counter;
|
||||
|
@ -39,8 +42,6 @@ void omapdss_display_init(struct omap_dss_device *dssdev)
|
|||
if (id < 0)
|
||||
id = disp_num_counter++;
|
||||
|
||||
dssdev->alias_id = id;
|
||||
|
||||
/* Use 'label' property for name, if it exists */
|
||||
of_property_read_string(dssdev->dev->of_node, "label", &dssdev->name);
|
||||
|
||||
|
@ -58,3 +59,22 @@ struct omap_dss_device *omapdss_display_get(struct omap_dss_device *output)
|
|||
return omapdss_device_get(output);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omapdss_display_get);
|
||||
|
||||
int omapdss_display_get_modes(struct drm_connector *connector,
|
||||
const struct videomode *vm)
|
||||
{
|
||||
struct drm_display_mode *mode;
|
||||
|
||||
mode = drm_mode_create(connector->dev);
|
||||
if (!mode)
|
||||
return 0;
|
||||
|
||||
drm_display_mode_from_videomode(vm, mode);
|
||||
|
||||
mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
|
||||
drm_mode_set_name(mode);
|
||||
drm_mode_probed_add(connector, mode);
|
||||
|
||||
return 1;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omapdss_display_get_modes);
|
||||
|
|
|
@ -47,8 +47,8 @@ struct dpi_data {
|
|||
|
||||
struct mutex lock;
|
||||
|
||||
struct videomode vm;
|
||||
struct dss_lcd_mgr_config mgr_config;
|
||||
unsigned long pixelclock;
|
||||
int data_lines;
|
||||
|
||||
struct omap_dss_device output;
|
||||
|
@ -347,16 +347,15 @@ static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req,
|
|||
|
||||
static int dpi_set_mode(struct dpi_data *dpi)
|
||||
{
|
||||
const struct videomode *vm = &dpi->vm;
|
||||
int lck_div = 0, pck_div = 0;
|
||||
unsigned long fck = 0;
|
||||
int r = 0;
|
||||
|
||||
if (dpi->pll)
|
||||
r = dpi_set_pll_clk(dpi, dpi->output.dispc_channel,
|
||||
vm->pixelclock, &fck, &lck_div, &pck_div);
|
||||
dpi->pixelclock, &fck, &lck_div, &pck_div);
|
||||
else
|
||||
r = dpi_set_dispc_clk(dpi, vm->pixelclock, &fck,
|
||||
r = dpi_set_dispc_clk(dpi, dpi->pixelclock, &fck,
|
||||
&lck_div, &pck_div);
|
||||
if (r)
|
||||
return r;
|
||||
|
@ -378,7 +377,7 @@ static void dpi_config_lcd_manager(struct dpi_data *dpi)
|
|||
dss_mgr_set_lcd_config(&dpi->output, &dpi->mgr_config);
|
||||
}
|
||||
|
||||
static int dpi_display_enable(struct omap_dss_device *dssdev)
|
||||
static void dpi_display_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
|
||||
struct omap_dss_device *out = &dpi->output;
|
||||
|
@ -386,12 +385,6 @@ static int dpi_display_enable(struct omap_dss_device *dssdev)
|
|||
|
||||
mutex_lock(&dpi->lock);
|
||||
|
||||
if (!out->dispc_channel_connected) {
|
||||
DSSERR("failed to enable display: no output/manager\n");
|
||||
r = -ENODEV;
|
||||
goto err_no_out_mgr;
|
||||
}
|
||||
|
||||
if (dpi->vdds_dsi_reg) {
|
||||
r = regulator_enable(dpi->vdds_dsi_reg);
|
||||
if (r)
|
||||
|
@ -426,7 +419,7 @@ static int dpi_display_enable(struct omap_dss_device *dssdev)
|
|||
|
||||
mutex_unlock(&dpi->lock);
|
||||
|
||||
return 0;
|
||||
return;
|
||||
|
||||
err_mgr_enable:
|
||||
err_set_mode:
|
||||
|
@ -439,9 +432,7 @@ err_get_dispc:
|
|||
if (dpi->vdds_dsi_reg)
|
||||
regulator_disable(dpi->vdds_dsi_reg);
|
||||
err_reg_enable:
|
||||
err_no_out_mgr:
|
||||
mutex_unlock(&dpi->lock);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void dpi_display_disable(struct omap_dss_device *dssdev)
|
||||
|
@ -467,7 +458,7 @@ static void dpi_display_disable(struct omap_dss_device *dssdev)
|
|||
}
|
||||
|
||||
static void dpi_set_timings(struct omap_dss_device *dssdev,
|
||||
const struct videomode *vm)
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
|
||||
|
||||
|
@ -475,13 +466,13 @@ static void dpi_set_timings(struct omap_dss_device *dssdev,
|
|||
|
||||
mutex_lock(&dpi->lock);
|
||||
|
||||
dpi->vm = *vm;
|
||||
dpi->pixelclock = mode->clock * 1000;
|
||||
|
||||
mutex_unlock(&dpi->lock);
|
||||
}
|
||||
|
||||
static int dpi_check_timings(struct omap_dss_device *dssdev,
|
||||
struct videomode *vm)
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
|
||||
int lck_div, pck_div;
|
||||
|
@ -490,20 +481,20 @@ static int dpi_check_timings(struct omap_dss_device *dssdev,
|
|||
struct dpi_clk_calc_ctx ctx;
|
||||
bool ok;
|
||||
|
||||
if (vm->hactive % 8 != 0)
|
||||
if (mode->hdisplay % 8 != 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (vm->pixelclock == 0)
|
||||
if (mode->clock == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (dpi->pll) {
|
||||
ok = dpi_pll_clk_calc(dpi, vm->pixelclock, &ctx);
|
||||
ok = dpi_pll_clk_calc(dpi, mode->clock * 1000, &ctx);
|
||||
if (!ok)
|
||||
return -EINVAL;
|
||||
|
||||
fck = ctx.pll_cinfo.clkout[ctx.clkout_idx];
|
||||
} else {
|
||||
ok = dpi_dss_clk_calc(dpi, vm->pixelclock, &ctx);
|
||||
ok = dpi_dss_clk_calc(dpi, mode->clock * 1000, &ctx);
|
||||
if (!ok)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -515,7 +506,7 @@ static int dpi_check_timings(struct omap_dss_device *dssdev,
|
|||
|
||||
pck = fck / lck_div / pck_div;
|
||||
|
||||
vm->pixelclock = pck;
|
||||
mode->clock = pck / 1000;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -596,23 +587,15 @@ static int dpi_connect(struct omap_dss_device *src,
|
|||
struct omap_dss_device *dst)
|
||||
{
|
||||
struct dpi_data *dpi = dpi_get_data_from_dssdev(dst);
|
||||
int r;
|
||||
|
||||
dpi_init_pll(dpi);
|
||||
|
||||
r = omapdss_device_connect(dst->dss, dst, dst->next);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dst->dispc_channel_connected = true;
|
||||
return 0;
|
||||
return omapdss_device_connect(dst->dss, dst, dst->next);
|
||||
}
|
||||
|
||||
static void dpi_disconnect(struct omap_dss_device *src,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
dst->dispc_channel_connected = false;
|
||||
|
||||
omapdss_device_disconnect(dst, dst->next);
|
||||
}
|
||||
|
||||
|
@ -651,25 +634,15 @@ static int dpi_init_output_port(struct dpi_data *dpi, struct device_node *port)
|
|||
|
||||
out->dev = &dpi->pdev->dev;
|
||||
out->id = OMAP_DSS_OUTPUT_DPI;
|
||||
out->output_type = OMAP_DISPLAY_TYPE_DPI;
|
||||
out->type = OMAP_DISPLAY_TYPE_DPI;
|
||||
out->dispc_channel = dpi_get_channel(dpi);
|
||||
out->of_ports = BIT(port_num);
|
||||
out->ops = &dpi_ops;
|
||||
out->owner = THIS_MODULE;
|
||||
|
||||
out->next = omapdss_of_find_connected_device(out->dev->of_node, 0);
|
||||
if (IS_ERR(out->next)) {
|
||||
if (PTR_ERR(out->next) != -EPROBE_DEFER)
|
||||
dev_err(out->dev, "failed to find video sink\n");
|
||||
return PTR_ERR(out->next);
|
||||
}
|
||||
|
||||
r = omapdss_output_validate(out);
|
||||
if (r) {
|
||||
omapdss_device_put(out->next);
|
||||
out->next = NULL;
|
||||
r = omapdss_device_init_output(out);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
omapdss_device_register(out);
|
||||
|
||||
|
@ -681,9 +654,8 @@ static void dpi_uninit_output_port(struct device_node *port)
|
|||
struct dpi_data *dpi = port->data;
|
||||
struct omap_dss_device *out = &dpi->output;
|
||||
|
||||
if (out->next)
|
||||
omapdss_device_put(out->next);
|
||||
omapdss_device_unregister(out);
|
||||
omapdss_device_cleanup_output(out);
|
||||
}
|
||||
|
||||
static const struct soc_device_attribute dpi_soc_devices[] = {
|
||||
|
|
|
@ -1342,12 +1342,9 @@ static int dsi_pll_enable(struct dss_pll *pll)
|
|||
*/
|
||||
dsi_enable_scp_clk(dsi);
|
||||
|
||||
if (!dsi->vdds_dsi_enabled) {
|
||||
r = regulator_enable(dsi->vdds_dsi_reg);
|
||||
if (r)
|
||||
goto err0;
|
||||
dsi->vdds_dsi_enabled = true;
|
||||
}
|
||||
r = regulator_enable(dsi->vdds_dsi_reg);
|
||||
if (r)
|
||||
goto err0;
|
||||
|
||||
/* XXX PLL does not come out of reset without this... */
|
||||
dispc_pck_free_enable(dsi->dss->dispc, 1);
|
||||
|
@ -1372,36 +1369,25 @@ static int dsi_pll_enable(struct dss_pll *pll)
|
|||
|
||||
return 0;
|
||||
err1:
|
||||
if (dsi->vdds_dsi_enabled) {
|
||||
regulator_disable(dsi->vdds_dsi_reg);
|
||||
dsi->vdds_dsi_enabled = false;
|
||||
}
|
||||
regulator_disable(dsi->vdds_dsi_reg);
|
||||
err0:
|
||||
dsi_disable_scp_clk(dsi);
|
||||
dsi_runtime_put(dsi);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void dsi_pll_uninit(struct dsi_data *dsi, bool disconnect_lanes)
|
||||
{
|
||||
dsi_pll_power(dsi, DSI_PLL_POWER_OFF);
|
||||
if (disconnect_lanes) {
|
||||
WARN_ON(!dsi->vdds_dsi_enabled);
|
||||
regulator_disable(dsi->vdds_dsi_reg);
|
||||
dsi->vdds_dsi_enabled = false;
|
||||
}
|
||||
|
||||
dsi_disable_scp_clk(dsi);
|
||||
dsi_runtime_put(dsi);
|
||||
|
||||
DSSDBG("PLL uninit done\n");
|
||||
}
|
||||
|
||||
static void dsi_pll_disable(struct dss_pll *pll)
|
||||
{
|
||||
struct dsi_data *dsi = container_of(pll, struct dsi_data, pll);
|
||||
|
||||
dsi_pll_uninit(dsi, true);
|
||||
dsi_pll_power(dsi, DSI_PLL_POWER_OFF);
|
||||
|
||||
regulator_disable(dsi->vdds_dsi_reg);
|
||||
|
||||
dsi_disable_scp_clk(dsi);
|
||||
dsi_runtime_put(dsi);
|
||||
|
||||
DSSDBG("PLL disable done\n");
|
||||
}
|
||||
|
||||
static int dsi_dump_dsi_clocks(struct seq_file *s, void *p)
|
||||
|
@ -3753,19 +3739,13 @@ static int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel)
|
|||
{
|
||||
struct dsi_data *dsi = to_dsi_data(dssdev);
|
||||
int bpp = dsi_get_pixel_size(dsi->pix_fmt);
|
||||
struct omap_dss_device *out = &dsi->output;
|
||||
u8 data_type;
|
||||
u16 word_count;
|
||||
int r;
|
||||
|
||||
if (!out->dispc_channel_connected) {
|
||||
DSSERR("failed to enable display: no output/manager\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
r = dsi_display_init_dispc(dsi);
|
||||
if (r)
|
||||
goto err_init_dispc;
|
||||
return r;
|
||||
|
||||
if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) {
|
||||
switch (dsi->pix_fmt) {
|
||||
|
@ -3814,7 +3794,6 @@ err_mgr_enable:
|
|||
}
|
||||
err_pix_fmt:
|
||||
dsi_display_uninit_dispc(dsi);
|
||||
err_init_dispc:
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -4096,11 +4075,11 @@ static int dsi_display_init_dsi(struct dsi_data *dsi)
|
|||
|
||||
r = dss_pll_enable(&dsi->pll);
|
||||
if (r)
|
||||
goto err0;
|
||||
return r;
|
||||
|
||||
r = dsi_configure_dsi_clocks(dsi);
|
||||
if (r)
|
||||
goto err1;
|
||||
goto err0;
|
||||
|
||||
dss_select_dsi_clk_source(dsi->dss, dsi->module_id,
|
||||
dsi->module_id == 0 ?
|
||||
|
@ -4108,6 +4087,14 @@ static int dsi_display_init_dsi(struct dsi_data *dsi)
|
|||
|
||||
DSSDBG("PLL OK\n");
|
||||
|
||||
if (!dsi->vdds_dsi_enabled) {
|
||||
r = regulator_enable(dsi->vdds_dsi_reg);
|
||||
if (r)
|
||||
goto err1;
|
||||
|
||||
dsi->vdds_dsi_enabled = true;
|
||||
}
|
||||
|
||||
r = dsi_cio_init(dsi);
|
||||
if (r)
|
||||
goto err2;
|
||||
|
@ -4136,10 +4123,13 @@ static int dsi_display_init_dsi(struct dsi_data *dsi)
|
|||
err3:
|
||||
dsi_cio_uninit(dsi);
|
||||
err2:
|
||||
dss_select_dsi_clk_source(dsi->dss, dsi->module_id, DSS_CLK_SRC_FCK);
|
||||
regulator_disable(dsi->vdds_dsi_reg);
|
||||
dsi->vdds_dsi_enabled = false;
|
||||
err1:
|
||||
dss_pll_disable(&dsi->pll);
|
||||
dss_select_dsi_clk_source(dsi->dss, dsi->module_id, DSS_CLK_SRC_FCK);
|
||||
err0:
|
||||
dss_pll_disable(&dsi->pll);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -4158,13 +4148,18 @@ static void dsi_display_uninit_dsi(struct dsi_data *dsi, bool disconnect_lanes,
|
|||
|
||||
dss_select_dsi_clk_source(dsi->dss, dsi->module_id, DSS_CLK_SRC_FCK);
|
||||
dsi_cio_uninit(dsi);
|
||||
dsi_pll_uninit(dsi, disconnect_lanes);
|
||||
dss_pll_disable(&dsi->pll);
|
||||
|
||||
if (disconnect_lanes) {
|
||||
regulator_disable(dsi->vdds_dsi_reg);
|
||||
dsi->vdds_dsi_enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
static int dsi_display_enable(struct omap_dss_device *dssdev)
|
||||
static void dsi_display_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct dsi_data *dsi = to_dsi_data(dssdev);
|
||||
int r = 0;
|
||||
int r;
|
||||
|
||||
DSSDBG("dsi_display_enable\n");
|
||||
|
||||
|
@ -4184,14 +4179,13 @@ static int dsi_display_enable(struct omap_dss_device *dssdev)
|
|||
|
||||
mutex_unlock(&dsi->lock);
|
||||
|
||||
return 0;
|
||||
return;
|
||||
|
||||
err_init_dsi:
|
||||
dsi_runtime_put(dsi);
|
||||
err_get_dsi:
|
||||
mutex_unlock(&dsi->lock);
|
||||
DSSDBG("dsi_display_enable FAILED\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
static void dsi_display_disable(struct omap_dss_device *dssdev,
|
||||
|
@ -4888,21 +4882,12 @@ static int dsi_get_clocks(struct dsi_data *dsi)
|
|||
static int dsi_connect(struct omap_dss_device *src,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = omapdss_device_connect(dst->dss, dst, dst->next);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dst->dispc_channel_connected = true;
|
||||
return 0;
|
||||
return omapdss_device_connect(dst->dss, dst, dst->next);
|
||||
}
|
||||
|
||||
static void dsi_disconnect(struct omap_dss_device *src,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
dst->dispc_channel_connected = false;
|
||||
|
||||
omapdss_device_disconnect(dst, dst->next);
|
||||
}
|
||||
|
||||
|
@ -5138,29 +5123,19 @@ static int dsi_init_output(struct dsi_data *dsi)
|
|||
out->id = dsi->module_id == 0 ?
|
||||
OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2;
|
||||
|
||||
out->output_type = OMAP_DISPLAY_TYPE_DSI;
|
||||
out->type = OMAP_DISPLAY_TYPE_DSI;
|
||||
out->name = dsi->module_id == 0 ? "dsi.0" : "dsi.1";
|
||||
out->dispc_channel = dsi_get_channel(dsi);
|
||||
out->ops = &dsi_ops;
|
||||
out->owner = THIS_MODULE;
|
||||
out->of_ports = BIT(0);
|
||||
out->bus_flags = DRM_BUS_FLAG_PIXDATA_POSEDGE
|
||||
out->bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE
|
||||
| DRM_BUS_FLAG_DE_HIGH
|
||||
| DRM_BUS_FLAG_SYNC_NEGEDGE;
|
||||
| DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE;
|
||||
|
||||
out->next = omapdss_of_find_connected_device(out->dev->of_node, 0);
|
||||
if (IS_ERR(out->next)) {
|
||||
if (PTR_ERR(out->next) != -EPROBE_DEFER)
|
||||
dev_err(out->dev, "failed to find video sink\n");
|
||||
return PTR_ERR(out->next);
|
||||
}
|
||||
|
||||
r = omapdss_output_validate(out);
|
||||
if (r) {
|
||||
omapdss_device_put(out->next);
|
||||
out->next = NULL;
|
||||
r = omapdss_device_init_output(out);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
omapdss_device_register(out);
|
||||
|
||||
|
@ -5171,9 +5146,8 @@ static void dsi_uninit_output(struct dsi_data *dsi)
|
|||
{
|
||||
struct omap_dss_device *out = &dsi->output;
|
||||
|
||||
if (out->next)
|
||||
omapdss_device_put(out->next);
|
||||
omapdss_device_unregister(out);
|
||||
omapdss_device_cleanup_output(out);
|
||||
}
|
||||
|
||||
static int dsi_probe_of(struct dsi_data *dsi)
|
||||
|
|
|
@ -12,71 +12,25 @@
|
|||
* more details.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
||||
#include "omapdss.h"
|
||||
|
||||
static struct device_node *
|
||||
dss_of_port_get_parent_device(struct device_node *port)
|
||||
{
|
||||
struct device_node *np;
|
||||
int i;
|
||||
|
||||
if (!port)
|
||||
return NULL;
|
||||
|
||||
np = of_get_parent(port);
|
||||
|
||||
for (i = 0; i < 2 && np; ++i) {
|
||||
struct property *prop;
|
||||
|
||||
prop = of_find_property(np, "compatible", NULL);
|
||||
|
||||
if (prop)
|
||||
return np;
|
||||
|
||||
np = of_get_next_parent(np);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct omap_dss_device *
|
||||
omapdss_of_find_connected_device(struct device_node *node, unsigned int port)
|
||||
{
|
||||
struct device_node *src_node;
|
||||
struct device_node *src_port;
|
||||
struct device_node *ep;
|
||||
struct omap_dss_device *src;
|
||||
u32 port_number = 0;
|
||||
struct device_node *remote_node;
|
||||
struct omap_dss_device *dssdev;
|
||||
|
||||
/* Get the endpoint... */
|
||||
ep = of_graph_get_endpoint_by_regs(node, port, 0);
|
||||
if (!ep)
|
||||
remote_node = of_graph_get_remote_node(node, port, 0);
|
||||
if (!remote_node)
|
||||
return NULL;
|
||||
|
||||
/* ... and its remote port... */
|
||||
src_port = of_graph_get_remote_port(ep);
|
||||
of_node_put(ep);
|
||||
if (!src_port)
|
||||
return NULL;
|
||||
dssdev = omapdss_find_device_by_node(remote_node);
|
||||
of_node_put(remote_node);
|
||||
|
||||
/* ... and the remote port's number and parent... */
|
||||
of_property_read_u32(src_port, "reg", &port_number);
|
||||
src_node = dss_of_port_get_parent_device(src_port);
|
||||
of_node_put(src_port);
|
||||
if (!src_node)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
/* ... and finally the connected device. */
|
||||
src = omapdss_find_device_by_port(src_node, port_number);
|
||||
of_node_put(src_node);
|
||||
|
||||
return src ? src : ERR_PTR(-EPROBE_DEFER);
|
||||
return dssdev ? dssdev : ERR_PTR(-EPROBE_DEFER);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(omapdss_of_find_connected_device);
|
||||
|
|
|
@ -1560,7 +1560,7 @@ static void dss_shutdown(struct platform_device *pdev)
|
|||
|
||||
DSSDBG("shutdown\n");
|
||||
|
||||
for_each_dss_display(dssdev) {
|
||||
for_each_dss_output(dssdev) {
|
||||
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
|
||||
dssdev->ops->disable(dssdev);
|
||||
}
|
||||
|
|
|
@ -249,15 +249,15 @@ static void hdmi_power_off_full(struct omap_hdmi *hdmi)
|
|||
}
|
||||
|
||||
static void hdmi_display_set_timings(struct omap_dss_device *dssdev,
|
||||
const struct videomode *vm)
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
|
||||
|
||||
mutex_lock(&hdmi->lock);
|
||||
|
||||
hdmi->cfg.vm = *vm;
|
||||
drm_display_mode_to_videomode(mode, &hdmi->cfg.vm);
|
||||
|
||||
dispc_set_tv_pclk(hdmi->dss->dispc, vm->pixelclock);
|
||||
dispc_set_tv_pclk(hdmi->dss->dispc, mode->clock * 1000);
|
||||
|
||||
mutex_unlock(&hdmi->lock);
|
||||
}
|
||||
|
@ -312,26 +312,20 @@ static void hdmi_stop_audio_stream(struct omap_hdmi *hd)
|
|||
hdmi_wp_audio_enable(&hd->wp, false);
|
||||
}
|
||||
|
||||
static int hdmi_display_enable(struct omap_dss_device *dssdev)
|
||||
static void hdmi_display_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
|
||||
unsigned long flags;
|
||||
int r = 0;
|
||||
int r;
|
||||
|
||||
DSSDBG("ENTER hdmi_display_enable\n");
|
||||
|
||||
mutex_lock(&hdmi->lock);
|
||||
|
||||
if (!dssdev->dispc_channel_connected) {
|
||||
DSSERR("failed to enable display: no output/manager\n");
|
||||
r = -ENODEV;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
r = hdmi_power_on_full(hdmi);
|
||||
if (r) {
|
||||
DSSERR("failed to power on device\n");
|
||||
goto err0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (hdmi->audio_configured) {
|
||||
|
@ -351,12 +345,8 @@ static int hdmi_display_enable(struct omap_dss_device *dssdev)
|
|||
hdmi->display_enabled = true;
|
||||
spin_unlock_irqrestore(&hdmi->audio_playing_lock, flags);
|
||||
|
||||
done:
|
||||
mutex_unlock(&hdmi->lock);
|
||||
return 0;
|
||||
|
||||
err0:
|
||||
mutex_unlock(&hdmi->lock);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void hdmi_display_disable(struct omap_dss_device *dssdev)
|
||||
|
@ -417,21 +407,12 @@ void hdmi4_core_disable(struct hdmi_core_data *core)
|
|||
static int hdmi_connect(struct omap_dss_device *src,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = omapdss_device_connect(dst->dss, dst, dst->next);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dst->dispc_channel_connected = true;
|
||||
return 0;
|
||||
return omapdss_device_connect(dst->dss, dst, dst->next);
|
||||
}
|
||||
|
||||
static void hdmi_disconnect(struct omap_dss_device *src,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
dst->dispc_channel_connected = false;
|
||||
|
||||
omapdss_device_disconnect(dst, dst->next);
|
||||
}
|
||||
|
||||
|
@ -698,7 +679,7 @@ static int hdmi4_init_output(struct omap_hdmi *hdmi)
|
|||
|
||||
out->dev = &hdmi->pdev->dev;
|
||||
out->id = OMAP_DSS_OUTPUT_HDMI;
|
||||
out->output_type = OMAP_DISPLAY_TYPE_HDMI;
|
||||
out->type = OMAP_DISPLAY_TYPE_HDMI;
|
||||
out->name = "hdmi.0";
|
||||
out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
|
||||
out->ops = &hdmi_ops;
|
||||
|
@ -706,19 +687,9 @@ static int hdmi4_init_output(struct omap_hdmi *hdmi)
|
|||
out->of_ports = BIT(0);
|
||||
out->ops_flags = OMAP_DSS_DEVICE_OP_EDID;
|
||||
|
||||
out->next = omapdss_of_find_connected_device(out->dev->of_node, 0);
|
||||
if (IS_ERR(out->next)) {
|
||||
if (PTR_ERR(out->next) != -EPROBE_DEFER)
|
||||
dev_err(out->dev, "failed to find video sink\n");
|
||||
return PTR_ERR(out->next);
|
||||
}
|
||||
|
||||
r = omapdss_output_validate(out);
|
||||
if (r) {
|
||||
omapdss_device_put(out->next);
|
||||
out->next = NULL;
|
||||
r = omapdss_device_init_output(out);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
omapdss_device_register(out);
|
||||
|
||||
|
@ -729,9 +700,8 @@ static void hdmi4_uninit_output(struct omap_hdmi *hdmi)
|
|||
{
|
||||
struct omap_dss_device *out = &hdmi->output;
|
||||
|
||||
if (out->next)
|
||||
omapdss_device_put(out->next);
|
||||
omapdss_device_unregister(out);
|
||||
omapdss_device_cleanup_output(out);
|
||||
}
|
||||
|
||||
static int hdmi4_probe_of(struct omap_hdmi *hdmi)
|
||||
|
|
|
@ -248,15 +248,15 @@ static void hdmi_power_off_full(struct omap_hdmi *hdmi)
|
|||
}
|
||||
|
||||
static void hdmi_display_set_timings(struct omap_dss_device *dssdev,
|
||||
const struct videomode *vm)
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
|
||||
|
||||
mutex_lock(&hdmi->lock);
|
||||
|
||||
hdmi->cfg.vm = *vm;
|
||||
drm_display_mode_to_videomode(mode, &hdmi->cfg.vm);
|
||||
|
||||
dispc_set_tv_pclk(hdmi->dss->dispc, vm->pixelclock);
|
||||
dispc_set_tv_pclk(hdmi->dss->dispc, mode->clock * 1000);
|
||||
|
||||
mutex_unlock(&hdmi->lock);
|
||||
}
|
||||
|
@ -320,26 +320,20 @@ static void hdmi_stop_audio_stream(struct omap_hdmi *hd)
|
|||
REG_FLD_MOD(hd->wp.base, HDMI_WP_SYSCONFIG, hd->wp_idlemode, 3, 2);
|
||||
}
|
||||
|
||||
static int hdmi_display_enable(struct omap_dss_device *dssdev)
|
||||
static void hdmi_display_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct omap_hdmi *hdmi = dssdev_to_hdmi(dssdev);
|
||||
unsigned long flags;
|
||||
int r = 0;
|
||||
int r;
|
||||
|
||||
DSSDBG("ENTER hdmi_display_enable\n");
|
||||
|
||||
mutex_lock(&hdmi->lock);
|
||||
|
||||
if (!dssdev->dispc_channel_connected) {
|
||||
DSSERR("failed to enable display: no output/manager\n");
|
||||
r = -ENODEV;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
r = hdmi_power_on_full(hdmi);
|
||||
if (r) {
|
||||
DSSERR("failed to power on device\n");
|
||||
goto err0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (hdmi->audio_configured) {
|
||||
|
@ -359,12 +353,8 @@ static int hdmi_display_enable(struct omap_dss_device *dssdev)
|
|||
hdmi->display_enabled = true;
|
||||
spin_unlock_irqrestore(&hdmi->audio_playing_lock, flags);
|
||||
|
||||
done:
|
||||
mutex_unlock(&hdmi->lock);
|
||||
return 0;
|
||||
|
||||
err0:
|
||||
mutex_unlock(&hdmi->lock);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void hdmi_display_disable(struct omap_dss_device *dssdev)
|
||||
|
@ -422,21 +412,12 @@ static void hdmi_core_disable(struct omap_hdmi *hdmi)
|
|||
static int hdmi_connect(struct omap_dss_device *src,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = omapdss_device_connect(dst->dss, dst, dst->next);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dst->dispc_channel_connected = true;
|
||||
return 0;
|
||||
return omapdss_device_connect(dst->dss, dst, dst->next);
|
||||
}
|
||||
|
||||
static void hdmi_disconnect(struct omap_dss_device *src,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
dst->dispc_channel_connected = false;
|
||||
|
||||
omapdss_device_disconnect(dst, dst->next);
|
||||
}
|
||||
|
||||
|
@ -682,7 +663,7 @@ static int hdmi5_init_output(struct omap_hdmi *hdmi)
|
|||
|
||||
out->dev = &hdmi->pdev->dev;
|
||||
out->id = OMAP_DSS_OUTPUT_HDMI;
|
||||
out->output_type = OMAP_DISPLAY_TYPE_HDMI;
|
||||
out->type = OMAP_DISPLAY_TYPE_HDMI;
|
||||
out->name = "hdmi.0";
|
||||
out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
|
||||
out->ops = &hdmi_ops;
|
||||
|
@ -690,19 +671,9 @@ static int hdmi5_init_output(struct omap_hdmi *hdmi)
|
|||
out->of_ports = BIT(0);
|
||||
out->ops_flags = OMAP_DSS_DEVICE_OP_EDID;
|
||||
|
||||
out->next = omapdss_of_find_connected_device(out->dev->of_node, 0);
|
||||
if (IS_ERR(out->next)) {
|
||||
if (PTR_ERR(out->next) != -EPROBE_DEFER)
|
||||
dev_err(out->dev, "failed to find video sink\n");
|
||||
return PTR_ERR(out->next);
|
||||
}
|
||||
|
||||
r = omapdss_output_validate(out);
|
||||
if (r) {
|
||||
omapdss_device_put(out->next);
|
||||
out->next = NULL;
|
||||
r = omapdss_device_init_output(out);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
omapdss_device_register(out);
|
||||
|
||||
|
@ -713,9 +684,8 @@ static void hdmi5_uninit_output(struct omap_hdmi *hdmi)
|
|||
{
|
||||
struct omap_dss_device *out = &hdmi->output;
|
||||
|
||||
if (out->next)
|
||||
omapdss_device_put(out->next);
|
||||
omapdss_device_unregister(out);
|
||||
omapdss_device_cleanup_output(out);
|
||||
}
|
||||
|
||||
static int hdmi5_probe_of(struct omap_hdmi *hdmi)
|
||||
|
|
|
@ -184,6 +184,22 @@ static const struct of_device_id omapdss_of_match[] __initconst = {
|
|||
{},
|
||||
};
|
||||
|
||||
static const struct of_device_id omapdss_of_fixups_whitelist[] __initconst = {
|
||||
{ .compatible = "composite-video-connector" },
|
||||
{ .compatible = "hdmi-connector" },
|
||||
{ .compatible = "lgphilips,lb035q02" },
|
||||
{ .compatible = "nec,nl8048hl11" },
|
||||
{ .compatible = "panel-dsi-cm" },
|
||||
{ .compatible = "sharp,ls037v7dw01" },
|
||||
{ .compatible = "sony,acx565akm" },
|
||||
{ .compatible = "svideo-connector" },
|
||||
{ .compatible = "ti,opa362" },
|
||||
{ .compatible = "ti,tpd12s015" },
|
||||
{ .compatible = "toppoly,td028ttec1" },
|
||||
{ .compatible = "tpo,td028ttec1" },
|
||||
{ .compatible = "tpo,td043mtea1" },
|
||||
};
|
||||
|
||||
static int __init omapdss_boot_init(void)
|
||||
{
|
||||
struct device_node *dss, *child;
|
||||
|
@ -210,7 +226,7 @@ static int __init omapdss_boot_init(void)
|
|||
n = list_first_entry(&dss_conv_list, struct dss_conv_node,
|
||||
list);
|
||||
|
||||
if (!n->root)
|
||||
if (of_match_node(omapdss_of_fixups_whitelist, n->node))
|
||||
omapdss_omapify_node(n->node);
|
||||
|
||||
list_del(&n->list);
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#define __OMAP_DRM_DSS_H
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <video/videomode.h>
|
||||
|
@ -68,6 +67,7 @@ struct dss_lcd_mgr_config;
|
|||
struct snd_aes_iec958;
|
||||
struct snd_cea_861_aud_if;
|
||||
struct hdmi_avi_infoframe;
|
||||
struct drm_connector;
|
||||
|
||||
enum omap_display_type {
|
||||
OMAP_DISPLAY_TYPE_NONE = 0,
|
||||
|
@ -360,15 +360,15 @@ struct omap_dss_device_ops {
|
|||
void (*disconnect)(struct omap_dss_device *dssdev,
|
||||
struct omap_dss_device *dst);
|
||||
|
||||
int (*enable)(struct omap_dss_device *dssdev);
|
||||
void (*pre_enable)(struct omap_dss_device *dssdev);
|
||||
void (*enable)(struct omap_dss_device *dssdev);
|
||||
void (*disable)(struct omap_dss_device *dssdev);
|
||||
void (*post_disable)(struct omap_dss_device *dssdev);
|
||||
|
||||
int (*check_timings)(struct omap_dss_device *dssdev,
|
||||
struct videomode *vm);
|
||||
void (*get_timings)(struct omap_dss_device *dssdev,
|
||||
struct videomode *vm);
|
||||
struct drm_display_mode *mode);
|
||||
void (*set_timings)(struct omap_dss_device *dssdev,
|
||||
const struct videomode *vm);
|
||||
const struct drm_display_mode *mode);
|
||||
|
||||
bool (*detect)(struct omap_dss_device *dssdev);
|
||||
|
||||
|
@ -380,6 +380,9 @@ struct omap_dss_device_ops {
|
|||
|
||||
int (*read_edid)(struct omap_dss_device *dssdev, u8 *buf, int len);
|
||||
|
||||
int (*get_modes)(struct omap_dss_device *dssdev,
|
||||
struct drm_connector *connector);
|
||||
|
||||
union {
|
||||
const struct omapdss_hdmi_ops hdmi;
|
||||
const struct omapdss_dsi_ops dsi;
|
||||
|
@ -390,42 +393,40 @@ struct omap_dss_device_ops {
|
|||
* enum omap_dss_device_ops_flag - Indicates which device ops are supported
|
||||
* @OMAP_DSS_DEVICE_OP_DETECT: The device supports output connection detection
|
||||
* @OMAP_DSS_DEVICE_OP_HPD: The device supports all hot-plug-related operations
|
||||
* @OMAP_DSS_DEVICE_OP_EDID: The device supports readind EDID
|
||||
* @OMAP_DSS_DEVICE_OP_EDID: The device supports reading EDID
|
||||
* @OMAP_DSS_DEVICE_OP_MODES: The device supports reading modes
|
||||
*/
|
||||
enum omap_dss_device_ops_flag {
|
||||
OMAP_DSS_DEVICE_OP_DETECT = BIT(0),
|
||||
OMAP_DSS_DEVICE_OP_HPD = BIT(1),
|
||||
OMAP_DSS_DEVICE_OP_EDID = BIT(2),
|
||||
};
|
||||
|
||||
enum omap_dss_device_type {
|
||||
OMAP_DSS_DEVICE_TYPE_OUTPUT = (1 << 0),
|
||||
OMAP_DSS_DEVICE_TYPE_DISPLAY = (1 << 1),
|
||||
OMAP_DSS_DEVICE_OP_MODES = BIT(3),
|
||||
};
|
||||
|
||||
struct omap_dss_device {
|
||||
struct kobject kobj;
|
||||
struct device *dev;
|
||||
|
||||
struct module *owner;
|
||||
|
||||
struct dss_device *dss;
|
||||
struct omap_dss_device *src;
|
||||
struct omap_dss_device *dst;
|
||||
struct omap_dss_device *next;
|
||||
struct drm_bridge *bridge;
|
||||
struct drm_panel *panel;
|
||||
|
||||
struct list_head list;
|
||||
|
||||
unsigned int alias_id;
|
||||
|
||||
enum omap_display_type type;
|
||||
/*
|
||||
* DSS output type that this device generates (for DSS internal devices)
|
||||
* or requires (for external encoders). Must be OMAP_DISPLAY_TYPE_NONE
|
||||
* for display devices (connectors and panels) and to non-zero value for
|
||||
* all other devices.
|
||||
* DSS type that this device generates (for DSS internal devices) or
|
||||
* requires (for external encoders, connectors and panels). Must be a
|
||||
* non-zero (different than OMAP_DISPLAY_TYPE_NONE) value.
|
||||
*/
|
||||
enum omap_display_type output_type;
|
||||
enum omap_display_type type;
|
||||
|
||||
/*
|
||||
* True if the device is a display (panel or connector) at the end of
|
||||
* the pipeline, false otherwise.
|
||||
*/
|
||||
bool display;
|
||||
|
||||
const char *name;
|
||||
|
||||
|
@ -434,9 +435,6 @@ struct omap_dss_device {
|
|||
unsigned long ops_flags;
|
||||
u32 bus_flags;
|
||||
|
||||
/* helper variable for driver suspend/resume */
|
||||
bool activate_after_resume;
|
||||
|
||||
enum omap_display_caps caps;
|
||||
|
||||
enum omap_dss_display_state state;
|
||||
|
@ -445,7 +443,6 @@ struct omap_dss_device {
|
|||
|
||||
/* DISPC channel for this output */
|
||||
enum omap_channel dispc_channel;
|
||||
bool dispc_channel_connected;
|
||||
|
||||
/* output instance */
|
||||
enum omap_dss_output_id id;
|
||||
|
@ -465,9 +462,6 @@ struct omap_dss_driver {
|
|||
int (*memory_read)(struct omap_dss_device *dssdev,
|
||||
void *buf, size_t size,
|
||||
u16 x, u16 y, u16 w, u16 h);
|
||||
|
||||
void (*get_size)(struct omap_dss_device *dssdev,
|
||||
unsigned int *width, unsigned int *height);
|
||||
};
|
||||
|
||||
struct dss_device *omapdss_get_dss(void);
|
||||
|
@ -477,32 +471,35 @@ static inline bool omapdss_is_initialized(void)
|
|||
return !!omapdss_get_dss();
|
||||
}
|
||||
|
||||
#define for_each_dss_display(d) \
|
||||
while ((d = omapdss_device_get_next(d, OMAP_DSS_DEVICE_TYPE_DISPLAY)) != NULL)
|
||||
void omapdss_display_init(struct omap_dss_device *dssdev);
|
||||
struct omap_dss_device *omapdss_display_get(struct omap_dss_device *output);
|
||||
int omapdss_display_get_modes(struct drm_connector *connector,
|
||||
const struct videomode *vm);
|
||||
|
||||
void omapdss_device_register(struct omap_dss_device *dssdev);
|
||||
void omapdss_device_unregister(struct omap_dss_device *dssdev);
|
||||
struct omap_dss_device *omapdss_device_get(struct omap_dss_device *dssdev);
|
||||
void omapdss_device_put(struct omap_dss_device *dssdev);
|
||||
struct omap_dss_device *omapdss_find_device_by_port(struct device_node *src,
|
||||
unsigned int port);
|
||||
struct omap_dss_device *omapdss_device_get_next(struct omap_dss_device *from,
|
||||
enum omap_dss_device_type type);
|
||||
struct omap_dss_device *omapdss_find_device_by_node(struct device_node *node);
|
||||
int omapdss_device_connect(struct dss_device *dss,
|
||||
struct omap_dss_device *src,
|
||||
struct omap_dss_device *dst);
|
||||
void omapdss_device_disconnect(struct omap_dss_device *src,
|
||||
struct omap_dss_device *dst);
|
||||
void omapdss_device_pre_enable(struct omap_dss_device *dssdev);
|
||||
void omapdss_device_enable(struct omap_dss_device *dssdev);
|
||||
void omapdss_device_disable(struct omap_dss_device *dssdev);
|
||||
void omapdss_device_post_disable(struct omap_dss_device *dssdev);
|
||||
|
||||
int omap_dss_get_num_overlay_managers(void);
|
||||
|
||||
int omap_dss_get_num_overlays(void);
|
||||
|
||||
#define for_each_dss_output(d) \
|
||||
while ((d = omapdss_device_get_next(d, OMAP_DSS_DEVICE_TYPE_OUTPUT)) != NULL)
|
||||
int omapdss_output_validate(struct omap_dss_device *out);
|
||||
while ((d = omapdss_device_next_output(d)) != NULL)
|
||||
struct omap_dss_device *omapdss_device_next_output(struct omap_dss_device *from);
|
||||
int omapdss_device_init_output(struct omap_dss_device *out);
|
||||
void omapdss_device_cleanup_output(struct omap_dss_device *out);
|
||||
|
||||
typedef void (*omap_dispc_isr_t) (void *arg, u32 mask);
|
||||
int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask);
|
||||
|
@ -511,11 +508,6 @@ int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask);
|
|||
int omapdss_compat_init(void);
|
||||
void omapdss_compat_uninit(void);
|
||||
|
||||
static inline bool omapdss_device_is_connected(struct omap_dss_device *dssdev)
|
||||
{
|
||||
return dssdev->src;
|
||||
}
|
||||
|
||||
static inline bool omapdss_device_is_enabled(struct omap_dss_device *dssdev)
|
||||
{
|
||||
return dssdev->state == OMAP_DSS_DISPLAY_ACTIVE;
|
||||
|
|
|
@ -20,20 +20,48 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_graph.h>
|
||||
|
||||
#include <drm/drm_panel.h>
|
||||
|
||||
#include "dss.h"
|
||||
#include "omapdss.h"
|
||||
|
||||
int omapdss_output_validate(struct omap_dss_device *out)
|
||||
int omapdss_device_init_output(struct omap_dss_device *out)
|
||||
{
|
||||
if (out->next && out->output_type != out->next->type) {
|
||||
struct device_node *remote_node;
|
||||
|
||||
remote_node = of_graph_get_remote_node(out->dev->of_node, 0, 0);
|
||||
if (!remote_node) {
|
||||
dev_dbg(out->dev, "failed to find video sink\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
out->next = omapdss_find_device_by_node(remote_node);
|
||||
out->bridge = of_drm_find_bridge(remote_node);
|
||||
out->panel = of_drm_find_panel(remote_node);
|
||||
if (IS_ERR(out->panel))
|
||||
out->panel = NULL;
|
||||
|
||||
of_node_put(remote_node);
|
||||
|
||||
if (out->next && out->type != out->next->type) {
|
||||
dev_err(out->dev, "output type and display type don't match\n");
|
||||
omapdss_device_put(out->next);
|
||||
out->next = NULL;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return out->next || out->bridge || out->panel ? 0 : -EPROBE_DEFER;
|
||||
}
|
||||
EXPORT_SYMBOL(omapdss_output_validate);
|
||||
EXPORT_SYMBOL(omapdss_device_init_output);
|
||||
|
||||
void omapdss_device_cleanup_output(struct omap_dss_device *out)
|
||||
{
|
||||
if (out->next)
|
||||
omapdss_device_put(out->next);
|
||||
}
|
||||
EXPORT_SYMBOL(omapdss_device_cleanup_output);
|
||||
|
||||
int dss_install_mgr_ops(struct dss_device *dss,
|
||||
const struct dss_mgr_ops *mgr_ops,
|
||||
|
|
|
@ -37,7 +37,7 @@ struct sdi_device {
|
|||
struct regulator *vdds_sdi_reg;
|
||||
|
||||
struct dss_lcd_mgr_config mgr_config;
|
||||
struct videomode vm;
|
||||
unsigned long pixelclock;
|
||||
int datapairs;
|
||||
|
||||
struct omap_dss_device output;
|
||||
|
@ -129,27 +129,22 @@ static void sdi_config_lcd_manager(struct sdi_device *sdi)
|
|||
dss_mgr_set_lcd_config(&sdi->output, &sdi->mgr_config);
|
||||
}
|
||||
|
||||
static int sdi_display_enable(struct omap_dss_device *dssdev)
|
||||
static void sdi_display_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct sdi_device *sdi = dssdev_to_sdi(dssdev);
|
||||
struct dispc_clock_info dispc_cinfo;
|
||||
unsigned long fck;
|
||||
int r;
|
||||
|
||||
if (!sdi->output.dispc_channel_connected) {
|
||||
DSSERR("failed to enable display: no output/manager\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
r = regulator_enable(sdi->vdds_sdi_reg);
|
||||
if (r)
|
||||
goto err_reg_enable;
|
||||
return;
|
||||
|
||||
r = dispc_runtime_get(sdi->dss->dispc);
|
||||
if (r)
|
||||
goto err_get_dispc;
|
||||
|
||||
r = sdi_calc_clock_div(sdi, sdi->vm.pixelclock, &fck, &dispc_cinfo);
|
||||
r = sdi_calc_clock_div(sdi, sdi->pixelclock, &fck, &dispc_cinfo);
|
||||
if (r)
|
||||
goto err_calc_clock_div;
|
||||
|
||||
|
@ -185,7 +180,7 @@ static int sdi_display_enable(struct omap_dss_device *dssdev)
|
|||
if (r)
|
||||
goto err_mgr_enable;
|
||||
|
||||
return 0;
|
||||
return;
|
||||
|
||||
err_mgr_enable:
|
||||
dss_sdi_disable(sdi->dss);
|
||||
|
@ -195,8 +190,6 @@ err_calc_clock_div:
|
|||
dispc_runtime_put(sdi->dss->dispc);
|
||||
err_get_dispc:
|
||||
regulator_disable(sdi->vdds_sdi_reg);
|
||||
err_reg_enable:
|
||||
return r;
|
||||
}
|
||||
|
||||
static void sdi_display_disable(struct omap_dss_device *dssdev)
|
||||
|
@ -213,36 +206,37 @@ static void sdi_display_disable(struct omap_dss_device *dssdev)
|
|||
}
|
||||
|
||||
static void sdi_set_timings(struct omap_dss_device *dssdev,
|
||||
const struct videomode *vm)
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
struct sdi_device *sdi = dssdev_to_sdi(dssdev);
|
||||
|
||||
sdi->vm = *vm;
|
||||
sdi->pixelclock = mode->clock * 1000;
|
||||
}
|
||||
|
||||
static int sdi_check_timings(struct omap_dss_device *dssdev,
|
||||
struct videomode *vm)
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct sdi_device *sdi = dssdev_to_sdi(dssdev);
|
||||
struct dispc_clock_info dispc_cinfo;
|
||||
unsigned long pixelclock = mode->clock * 1000;
|
||||
unsigned long fck;
|
||||
unsigned long pck;
|
||||
int r;
|
||||
|
||||
if (vm->pixelclock == 0)
|
||||
if (pixelclock == 0)
|
||||
return -EINVAL;
|
||||
|
||||
r = sdi_calc_clock_div(sdi, vm->pixelclock, &fck, &dispc_cinfo);
|
||||
r = sdi_calc_clock_div(sdi, pixelclock, &fck, &dispc_cinfo);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
pck = fck / dispc_cinfo.lck_div / dispc_cinfo.pck_div;
|
||||
|
||||
if (pck != vm->pixelclock) {
|
||||
if (pck != pixelclock) {
|
||||
DSSWARN("Pixel clock adjusted from %lu Hz to %lu Hz\n",
|
||||
vm->pixelclock, pck);
|
||||
pixelclock, pck);
|
||||
|
||||
vm->pixelclock = pck;
|
||||
mode->clock = pck / 1000;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -251,21 +245,12 @@ static int sdi_check_timings(struct omap_dss_device *dssdev,
|
|||
static int sdi_connect(struct omap_dss_device *src,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = omapdss_device_connect(dst->dss, dst, dst->next);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dst->dispc_channel_connected = true;
|
||||
return 0;
|
||||
return omapdss_device_connect(dst->dss, dst, dst->next);
|
||||
}
|
||||
|
||||
static void sdi_disconnect(struct omap_dss_device *src,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
dst->dispc_channel_connected = false;
|
||||
|
||||
omapdss_device_disconnect(dst, dst->next);
|
||||
}
|
||||
|
||||
|
@ -287,29 +272,19 @@ static int sdi_init_output(struct sdi_device *sdi)
|
|||
|
||||
out->dev = &sdi->pdev->dev;
|
||||
out->id = OMAP_DSS_OUTPUT_SDI;
|
||||
out->output_type = OMAP_DISPLAY_TYPE_SDI;
|
||||
out->type = OMAP_DISPLAY_TYPE_SDI;
|
||||
out->name = "sdi.0";
|
||||
out->dispc_channel = OMAP_DSS_CHANNEL_LCD;
|
||||
/* We have SDI only on OMAP3, where it's on port 1 */
|
||||
out->of_ports = BIT(1);
|
||||
out->ops = &sdi_ops;
|
||||
out->owner = THIS_MODULE;
|
||||
out->bus_flags = DRM_BUS_FLAG_PIXDATA_POSEDGE /* 15.5.9.1.2 */
|
||||
| DRM_BUS_FLAG_SYNC_POSEDGE;
|
||||
out->bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE /* 15.5.9.1.2 */
|
||||
| DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE;
|
||||
|
||||
out->next = omapdss_of_find_connected_device(out->dev->of_node, 1);
|
||||
if (IS_ERR(out->next)) {
|
||||
if (PTR_ERR(out->next) != -EPROBE_DEFER)
|
||||
dev_err(out->dev, "failed to find video sink\n");
|
||||
return PTR_ERR(out->next);
|
||||
}
|
||||
|
||||
r = omapdss_output_validate(out);
|
||||
if (r) {
|
||||
omapdss_device_put(out->next);
|
||||
out->next = NULL;
|
||||
r = omapdss_device_init_output(out);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
omapdss_device_register(out);
|
||||
|
||||
|
@ -318,9 +293,8 @@ static int sdi_init_output(struct sdi_device *sdi)
|
|||
|
||||
static void sdi_uninit_output(struct sdi_device *sdi)
|
||||
{
|
||||
if (sdi->output.next)
|
||||
omapdss_device_put(sdi->output.next);
|
||||
omapdss_device_unregister(&sdi->output);
|
||||
omapdss_device_cleanup_output(&sdi->output);
|
||||
}
|
||||
|
||||
int sdi_init_port(struct dss_device *dss, struct platform_device *pdev,
|
||||
|
|
|
@ -267,63 +267,40 @@ enum venc_videomode {
|
|||
VENC_MODE_NTSC,
|
||||
};
|
||||
|
||||
static const struct videomode omap_dss_pal_vm = {
|
||||
.hactive = 720,
|
||||
.vactive = 574,
|
||||
.pixelclock = 13500000,
|
||||
.hsync_len = 64,
|
||||
.hfront_porch = 12,
|
||||
.hback_porch = 68,
|
||||
.vsync_len = 5,
|
||||
.vfront_porch = 5,
|
||||
.vback_porch = 41,
|
||||
static const struct drm_display_mode omap_dss_pal_mode = {
|
||||
.hdisplay = 720,
|
||||
.hsync_start = 732,
|
||||
.hsync_end = 796,
|
||||
.htotal = 864,
|
||||
.vdisplay = 574,
|
||||
.vsync_start = 579,
|
||||
.vsync_end = 584,
|
||||
.vtotal = 625,
|
||||
.clock = 13500,
|
||||
|
||||
.flags = DISPLAY_FLAGS_INTERLACED | DISPLAY_FLAGS_HSYNC_LOW |
|
||||
DISPLAY_FLAGS_VSYNC_LOW | DISPLAY_FLAGS_DE_HIGH |
|
||||
DISPLAY_FLAGS_PIXDATA_POSEDGE |
|
||||
DISPLAY_FLAGS_SYNC_NEGEDGE,
|
||||
.flags = DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_NHSYNC |
|
||||
DRM_MODE_FLAG_NVSYNC,
|
||||
};
|
||||
|
||||
static const struct videomode omap_dss_ntsc_vm = {
|
||||
.hactive = 720,
|
||||
.vactive = 482,
|
||||
.pixelclock = 13500000,
|
||||
.hsync_len = 64,
|
||||
.hfront_porch = 16,
|
||||
.hback_porch = 58,
|
||||
.vsync_len = 6,
|
||||
.vfront_porch = 6,
|
||||
.vback_porch = 31,
|
||||
static const struct drm_display_mode omap_dss_ntsc_mode = {
|
||||
.hdisplay = 720,
|
||||
.hsync_start = 736,
|
||||
.hsync_end = 800,
|
||||
.htotal = 858,
|
||||
.vdisplay = 482,
|
||||
.vsync_start = 488,
|
||||
.vsync_end = 494,
|
||||
.vtotal = 525,
|
||||
.clock = 13500,
|
||||
|
||||
.flags = DISPLAY_FLAGS_INTERLACED | DISPLAY_FLAGS_HSYNC_LOW |
|
||||
DISPLAY_FLAGS_VSYNC_LOW | DISPLAY_FLAGS_DE_HIGH |
|
||||
DISPLAY_FLAGS_PIXDATA_POSEDGE |
|
||||
DISPLAY_FLAGS_SYNC_NEGEDGE,
|
||||
.flags = DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_NHSYNC |
|
||||
DRM_MODE_FLAG_NVSYNC,
|
||||
};
|
||||
|
||||
static enum venc_videomode venc_get_videomode(const struct videomode *vm)
|
||||
{
|
||||
if (!(vm->flags & DISPLAY_FLAGS_INTERLACED))
|
||||
return VENC_MODE_UNKNOWN;
|
||||
|
||||
if (vm->pixelclock == omap_dss_pal_vm.pixelclock &&
|
||||
vm->hactive == omap_dss_pal_vm.hactive &&
|
||||
vm->vactive == omap_dss_pal_vm.vactive)
|
||||
return VENC_MODE_PAL;
|
||||
|
||||
if (vm->pixelclock == omap_dss_ntsc_vm.pixelclock &&
|
||||
vm->hactive == omap_dss_ntsc_vm.hactive &&
|
||||
vm->vactive == omap_dss_ntsc_vm.vactive)
|
||||
return VENC_MODE_NTSC;
|
||||
|
||||
return VENC_MODE_UNKNOWN;
|
||||
}
|
||||
|
||||
struct venc_device {
|
||||
struct platform_device *pdev;
|
||||
void __iomem *base;
|
||||
struct mutex venc_lock;
|
||||
u32 wss_data;
|
||||
struct regulator *vdda_dac_reg;
|
||||
struct dss_device *dss;
|
||||
|
||||
|
@ -331,7 +308,7 @@ struct venc_device {
|
|||
|
||||
struct clk *tv_dac_clk;
|
||||
|
||||
struct videomode vm;
|
||||
const struct venc_config *config;
|
||||
enum omap_dss_venc_type type;
|
||||
bool invert_polarity;
|
||||
bool requires_tv_dac_clk;
|
||||
|
@ -367,8 +344,7 @@ static void venc_write_config(struct venc_device *venc,
|
|||
venc_write_reg(venc, VENC_BLACK_LEVEL, config->black_level);
|
||||
venc_write_reg(venc, VENC_BLANK_LEVEL, config->blank_level);
|
||||
venc_write_reg(venc, VENC_M_CONTROL, config->m_control);
|
||||
venc_write_reg(venc, VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data |
|
||||
venc->wss_data);
|
||||
venc_write_reg(venc, VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data);
|
||||
venc_write_reg(venc, VENC_S_CARR, config->s_carr);
|
||||
venc_write_reg(venc, VENC_L21__WC_CTL, config->l21__wc_ctl);
|
||||
venc_write_reg(venc, VENC_SAVID__EAVID, config->savid__eavid);
|
||||
|
@ -452,18 +428,6 @@ static void venc_runtime_put(struct venc_device *venc)
|
|||
WARN_ON(r < 0 && r != -ENOSYS);
|
||||
}
|
||||
|
||||
static const struct venc_config *venc_timings_to_config(const struct videomode *vm)
|
||||
{
|
||||
switch (venc_get_videomode(vm)) {
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
case VENC_MODE_PAL:
|
||||
return &venc_config_pal_trm;
|
||||
case VENC_MODE_NTSC:
|
||||
return &venc_config_ntsc_trm;
|
||||
}
|
||||
}
|
||||
|
||||
static int venc_power_on(struct venc_device *venc)
|
||||
{
|
||||
u32 l;
|
||||
|
@ -474,7 +438,7 @@ static int venc_power_on(struct venc_device *venc)
|
|||
goto err0;
|
||||
|
||||
venc_reset(venc);
|
||||
venc_write_config(venc, venc_timings_to_config(&venc->vm));
|
||||
venc_write_config(venc, venc->config);
|
||||
|
||||
dss_set_venc_output(venc->dss, venc->type);
|
||||
dss_set_dac_pwrdn_bgz(venc->dss, 1);
|
||||
|
@ -524,33 +488,17 @@ static void venc_power_off(struct venc_device *venc)
|
|||
venc_runtime_put(venc);
|
||||
}
|
||||
|
||||
static int venc_display_enable(struct omap_dss_device *dssdev)
|
||||
static void venc_display_enable(struct omap_dss_device *dssdev)
|
||||
{
|
||||
struct venc_device *venc = dssdev_to_venc(dssdev);
|
||||
int r;
|
||||
|
||||
DSSDBG("venc_display_enable\n");
|
||||
|
||||
mutex_lock(&venc->venc_lock);
|
||||
|
||||
if (!dssdev->dispc_channel_connected) {
|
||||
DSSERR("Failed to enable display: no output/manager\n");
|
||||
r = -ENODEV;
|
||||
goto err0;
|
||||
}
|
||||
|
||||
r = venc_power_on(venc);
|
||||
if (r)
|
||||
goto err0;
|
||||
|
||||
venc->wss_data = 0;
|
||||
venc_power_on(venc);
|
||||
|
||||
mutex_unlock(&venc->venc_lock);
|
||||
|
||||
return 0;
|
||||
err0:
|
||||
mutex_unlock(&venc->venc_lock);
|
||||
return r;
|
||||
}
|
||||
|
||||
static void venc_display_disable(struct omap_dss_device *dssdev)
|
||||
|
@ -566,30 +514,70 @@ static void venc_display_disable(struct omap_dss_device *dssdev)
|
|||
mutex_unlock(&venc->venc_lock);
|
||||
}
|
||||
|
||||
static void venc_get_timings(struct omap_dss_device *dssdev,
|
||||
struct videomode *vm)
|
||||
static int venc_get_modes(struct omap_dss_device *dssdev,
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
struct venc_device *venc = dssdev_to_venc(dssdev);
|
||||
static const struct drm_display_mode *modes[] = {
|
||||
&omap_dss_pal_mode,
|
||||
&omap_dss_ntsc_mode,
|
||||
};
|
||||
unsigned int i;
|
||||
|
||||
mutex_lock(&venc->venc_lock);
|
||||
*vm = venc->vm;
|
||||
mutex_unlock(&venc->venc_lock);
|
||||
for (i = 0; i < ARRAY_SIZE(modes); ++i) {
|
||||
struct drm_display_mode *mode;
|
||||
|
||||
mode = drm_mode_duplicate(connector->dev, modes[i]);
|
||||
if (!mode)
|
||||
return i;
|
||||
|
||||
mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
|
||||
drm_mode_set_name(mode);
|
||||
drm_mode_probed_add(connector, mode);
|
||||
}
|
||||
|
||||
return ARRAY_SIZE(modes);
|
||||
}
|
||||
|
||||
static enum venc_videomode venc_get_videomode(const struct drm_display_mode *mode)
|
||||
{
|
||||
if (!(mode->flags & DRM_MODE_FLAG_INTERLACE))
|
||||
return VENC_MODE_UNKNOWN;
|
||||
|
||||
if (mode->clock == omap_dss_pal_mode.clock &&
|
||||
mode->hdisplay == omap_dss_pal_mode.hdisplay &&
|
||||
mode->vdisplay == omap_dss_pal_mode.vdisplay)
|
||||
return VENC_MODE_PAL;
|
||||
|
||||
if (mode->clock == omap_dss_ntsc_mode.clock &&
|
||||
mode->hdisplay == omap_dss_ntsc_mode.hdisplay &&
|
||||
mode->vdisplay == omap_dss_ntsc_mode.vdisplay)
|
||||
return VENC_MODE_NTSC;
|
||||
|
||||
return VENC_MODE_UNKNOWN;
|
||||
}
|
||||
|
||||
static void venc_set_timings(struct omap_dss_device *dssdev,
|
||||
const struct videomode *vm)
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
struct venc_device *venc = dssdev_to_venc(dssdev);
|
||||
enum venc_videomode venc_mode = venc_get_videomode(mode);
|
||||
|
||||
DSSDBG("venc_set_timings\n");
|
||||
|
||||
mutex_lock(&venc->venc_lock);
|
||||
|
||||
/* Reset WSS data when the TV standard changes. */
|
||||
if (memcmp(&venc->vm, vm, sizeof(*vm)))
|
||||
venc->wss_data = 0;
|
||||
switch (venc_mode) {
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
/* Fall-through */
|
||||
case VENC_MODE_PAL:
|
||||
venc->config = &venc_config_pal_trm;
|
||||
break;
|
||||
|
||||
venc->vm = *vm;
|
||||
case VENC_MODE_NTSC:
|
||||
venc->config = &venc_config_ntsc_trm;
|
||||
break;
|
||||
}
|
||||
|
||||
dispc_set_tv_pclk(venc->dss->dispc, 13500000);
|
||||
|
||||
|
@ -597,22 +585,26 @@ static void venc_set_timings(struct omap_dss_device *dssdev,
|
|||
}
|
||||
|
||||
static int venc_check_timings(struct omap_dss_device *dssdev,
|
||||
struct videomode *vm)
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
DSSDBG("venc_check_timings\n");
|
||||
|
||||
switch (venc_get_videomode(vm)) {
|
||||
switch (venc_get_videomode(mode)) {
|
||||
case VENC_MODE_PAL:
|
||||
*vm = omap_dss_pal_vm;
|
||||
return 0;
|
||||
drm_mode_copy(mode, &omap_dss_pal_mode);
|
||||
break;
|
||||
|
||||
case VENC_MODE_NTSC:
|
||||
*vm = omap_dss_ntsc_vm;
|
||||
return 0;
|
||||
drm_mode_copy(mode, &omap_dss_ntsc_mode);
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
|
||||
drm_mode_set_name(mode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int venc_dump_regs(struct seq_file *s, void *p)
|
||||
|
@ -695,21 +687,12 @@ static int venc_get_clocks(struct venc_device *venc)
|
|||
static int venc_connect(struct omap_dss_device *src,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = omapdss_device_connect(dst->dss, dst, dst->next);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
dst->dispc_channel_connected = true;
|
||||
return 0;
|
||||
return omapdss_device_connect(dst->dss, dst, dst->next);
|
||||
}
|
||||
|
||||
static void venc_disconnect(struct omap_dss_device *src,
|
||||
struct omap_dss_device *dst)
|
||||
{
|
||||
dst->dispc_channel_connected = false;
|
||||
|
||||
omapdss_device_disconnect(dst, dst->next);
|
||||
}
|
||||
|
||||
|
@ -721,8 +704,9 @@ static const struct omap_dss_device_ops venc_ops = {
|
|||
.disable = venc_display_disable,
|
||||
|
||||
.check_timings = venc_check_timings,
|
||||
.get_timings = venc_get_timings,
|
||||
.set_timings = venc_set_timings,
|
||||
|
||||
.get_modes = venc_get_modes,
|
||||
};
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
|
@ -776,26 +760,17 @@ static int venc_init_output(struct venc_device *venc)
|
|||
|
||||
out->dev = &venc->pdev->dev;
|
||||
out->id = OMAP_DSS_OUTPUT_VENC;
|
||||
out->output_type = OMAP_DISPLAY_TYPE_VENC;
|
||||
out->type = OMAP_DISPLAY_TYPE_VENC;
|
||||
out->name = "venc.0";
|
||||
out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
|
||||
out->ops = &venc_ops;
|
||||
out->owner = THIS_MODULE;
|
||||
out->of_ports = BIT(0);
|
||||
out->ops_flags = OMAP_DSS_DEVICE_OP_MODES;
|
||||
|
||||
out->next = omapdss_of_find_connected_device(out->dev->of_node, 0);
|
||||
if (IS_ERR(out->next)) {
|
||||
if (PTR_ERR(out->next) != -EPROBE_DEFER)
|
||||
dev_err(out->dev, "failed to find video sink\n");
|
||||
return PTR_ERR(out->next);
|
||||
}
|
||||
|
||||
r = omapdss_output_validate(out);
|
||||
if (r) {
|
||||
omapdss_device_put(out->next);
|
||||
out->next = NULL;
|
||||
r = omapdss_device_init_output(out);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
omapdss_device_register(out);
|
||||
|
||||
|
@ -804,9 +779,8 @@ static int venc_init_output(struct venc_device *venc)
|
|||
|
||||
static void venc_uninit_output(struct venc_device *venc)
|
||||
{
|
||||
if (venc->output.next)
|
||||
omapdss_device_put(venc->output.next);
|
||||
omapdss_device_unregister(&venc->output);
|
||||
omapdss_device_cleanup_output(&venc->output);
|
||||
}
|
||||
|
||||
static int venc_probe_of(struct venc_device *venc)
|
||||
|
@ -878,8 +852,7 @@ static int venc_probe(struct platform_device *pdev)
|
|||
|
||||
mutex_init(&venc->venc_lock);
|
||||
|
||||
venc->wss_data = 0;
|
||||
venc->vm = omap_dss_pal_vm;
|
||||
venc->config = &venc_config_pal_trm;
|
||||
|
||||
venc_mem = platform_get_resource(venc->pdev, IORESOURCE_MEM, 0);
|
||||
venc->base = devm_ioremap_resource(&pdev->dev, venc_mem);
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_panel.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
|
||||
#include "omap_drv.h"
|
||||
|
@ -30,24 +31,27 @@
|
|||
struct omap_connector {
|
||||
struct drm_connector base;
|
||||
struct omap_dss_device *output;
|
||||
struct omap_dss_device *display;
|
||||
struct omap_dss_device *hpd;
|
||||
bool hdmi_mode;
|
||||
};
|
||||
|
||||
static void omap_connector_hpd_notify(struct drm_connector *connector,
|
||||
struct omap_dss_device *src,
|
||||
enum drm_connector_status status)
|
||||
{
|
||||
if (status == connector_status_disconnected) {
|
||||
/*
|
||||
* If the source is an HDMI encoder, notify it of disconnection.
|
||||
* This is required to let the HDMI encoder reset any internal
|
||||
* state related to connection status, such as the CEC address.
|
||||
*/
|
||||
if (src && src->type == OMAP_DISPLAY_TYPE_HDMI &&
|
||||
src->ops->hdmi.lost_hotplug)
|
||||
src->ops->hdmi.lost_hotplug(src);
|
||||
struct omap_connector *omap_connector = to_omap_connector(connector);
|
||||
struct omap_dss_device *dssdev;
|
||||
|
||||
if (status != connector_status_disconnected)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Notify all devics in the pipeline of disconnection. This is required
|
||||
* to let the HDMI encoders reset their internal state related to
|
||||
* connection status, such as the CEC address.
|
||||
*/
|
||||
for (dssdev = omap_connector->output; dssdev; dssdev = dssdev->next) {
|
||||
if (dssdev->ops && dssdev->ops->hdmi.lost_hotplug)
|
||||
dssdev->ops->hdmi.lost_hotplug(dssdev);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,7 +71,7 @@ static void omap_connector_hpd_cb(void *cb_data,
|
|||
if (old_status == status)
|
||||
return;
|
||||
|
||||
omap_connector_hpd_notify(connector, omap_connector->hpd, status);
|
||||
omap_connector_hpd_notify(connector, status);
|
||||
|
||||
drm_kms_helper_hotplug_event(dev);
|
||||
}
|
||||
|
@ -103,20 +107,20 @@ omap_connector_find_device(struct drm_connector *connector,
|
|||
enum omap_dss_device_ops_flag op)
|
||||
{
|
||||
struct omap_connector *omap_connector = to_omap_connector(connector);
|
||||
struct omap_dss_device *dssdev;
|
||||
struct omap_dss_device *dssdev = NULL;
|
||||
struct omap_dss_device *d;
|
||||
|
||||
for (dssdev = omap_connector->display; dssdev; dssdev = dssdev->src) {
|
||||
if (dssdev->ops_flags & op)
|
||||
return dssdev;
|
||||
for (d = omap_connector->output; d; d = d->next) {
|
||||
if (d->ops_flags & op)
|
||||
dssdev = d;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return dssdev;
|
||||
}
|
||||
|
||||
static enum drm_connector_status omap_connector_detect(
|
||||
struct drm_connector *connector, bool force)
|
||||
{
|
||||
struct omap_connector *omap_connector = to_omap_connector(connector);
|
||||
struct omap_dss_device *dssdev;
|
||||
enum drm_connector_status status;
|
||||
|
||||
|
@ -128,13 +132,12 @@ static enum drm_connector_status omap_connector_detect(
|
|||
? connector_status_connected
|
||||
: connector_status_disconnected;
|
||||
|
||||
omap_connector_hpd_notify(connector, dssdev->src, status);
|
||||
omap_connector_hpd_notify(connector, status);
|
||||
} else {
|
||||
switch (omap_connector->display->type) {
|
||||
case OMAP_DISPLAY_TYPE_DPI:
|
||||
case OMAP_DISPLAY_TYPE_DBI:
|
||||
case OMAP_DISPLAY_TYPE_SDI:
|
||||
case OMAP_DISPLAY_TYPE_DSI:
|
||||
switch (connector->connector_type) {
|
||||
case DRM_MODE_CONNECTOR_DPI:
|
||||
case DRM_MODE_CONNECTOR_LVDS:
|
||||
case DRM_MODE_CONNECTOR_DSI:
|
||||
status = connector_status_connected;
|
||||
break;
|
||||
default:
|
||||
|
@ -143,7 +146,7 @@ static enum drm_connector_status omap_connector_detect(
|
|||
}
|
||||
}
|
||||
|
||||
VERB("%s: %d (force=%d)", omap_connector->display->name, status, force);
|
||||
VERB("%s: %d (force=%d)", connector->name, status, force);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
@ -152,7 +155,7 @@ static void omap_connector_destroy(struct drm_connector *connector)
|
|||
{
|
||||
struct omap_connector *omap_connector = to_omap_connector(connector);
|
||||
|
||||
DBG("%s", omap_connector->display->name);
|
||||
DBG("%s", connector->name);
|
||||
|
||||
if (omap_connector->hpd) {
|
||||
struct omap_dss_device *hpd = omap_connector->hpd;
|
||||
|
@ -166,7 +169,6 @@ static void omap_connector_destroy(struct drm_connector *connector)
|
|||
drm_connector_cleanup(connector);
|
||||
|
||||
omapdss_device_put(omap_connector->output);
|
||||
omapdss_device_put(omap_connector->display);
|
||||
|
||||
kfree(omap_connector);
|
||||
}
|
||||
|
@ -212,10 +214,8 @@ static int omap_connector_get_modes(struct drm_connector *connector)
|
|||
{
|
||||
struct omap_connector *omap_connector = to_omap_connector(connector);
|
||||
struct omap_dss_device *dssdev;
|
||||
struct drm_display_mode *mode;
|
||||
struct videomode vm = {0};
|
||||
|
||||
DBG("%s", omap_connector->display->name);
|
||||
DBG("%s", connector->name);
|
||||
|
||||
/*
|
||||
* If display exposes EDID, then we parse that in the normal way to
|
||||
|
@ -227,89 +227,71 @@ static int omap_connector_get_modes(struct drm_connector *connector)
|
|||
return omap_connector_get_modes_edid(connector, dssdev);
|
||||
|
||||
/*
|
||||
* Otherwise we have either a fixed resolution panel or an output that
|
||||
* doesn't support modes discovery (e.g. DVI or VGA with the DDC bus
|
||||
* unconnected, or analog TV). Start by querying the size.
|
||||
* Otherwise if the display pipeline reports modes (e.g. with a fixed
|
||||
* resolution panel or an analog TV output), query it.
|
||||
*/
|
||||
dssdev = omap_connector->display;
|
||||
if (dssdev->driver && dssdev->driver->get_size)
|
||||
dssdev->driver->get_size(dssdev,
|
||||
&connector->display_info.width_mm,
|
||||
&connector->display_info.height_mm);
|
||||
dssdev = omap_connector_find_device(connector,
|
||||
OMAP_DSS_DEVICE_OP_MODES);
|
||||
if (dssdev)
|
||||
return dssdev->ops->get_modes(dssdev, connector);
|
||||
|
||||
/*
|
||||
* Iterate over the pipeline to find the first device that can provide
|
||||
* timing information. If we can't find any, we just let the KMS core
|
||||
* add the default modes.
|
||||
* Otherwise if the display pipeline uses a drm_panel, we delegate the
|
||||
* operation to the panel API.
|
||||
*/
|
||||
for (dssdev = omap_connector->display; dssdev; dssdev = dssdev->src) {
|
||||
if (dssdev->ops->get_timings)
|
||||
break;
|
||||
}
|
||||
if (!dssdev)
|
||||
return 0;
|
||||
if (omap_connector->output->panel)
|
||||
return drm_panel_get_modes(omap_connector->output->panel);
|
||||
|
||||
/* Add a single mode corresponding to the fixed panel timings. */
|
||||
mode = drm_mode_create(connector->dev);
|
||||
if (!mode)
|
||||
return 0;
|
||||
|
||||
dssdev->ops->get_timings(dssdev, &vm);
|
||||
|
||||
drm_display_mode_from_videomode(&vm, mode);
|
||||
|
||||
mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
|
||||
drm_mode_set_name(mode);
|
||||
drm_mode_probed_add(connector, mode);
|
||||
|
||||
return 1;
|
||||
/*
|
||||
* We can't retrieve modes, which can happen for instance for a DVI or
|
||||
* VGA output with the DDC bus unconnected. The KMS core will add the
|
||||
* default modes.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omap_connector_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
enum drm_mode_status omap_connector_mode_fixup(struct omap_dss_device *dssdev,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct omap_connector *omap_connector = to_omap_connector(connector);
|
||||
enum omap_channel channel = omap_connector->output->dispc_channel;
|
||||
struct omap_drm_private *priv = connector->dev->dev_private;
|
||||
struct omap_dss_device *dssdev;
|
||||
struct videomode vm = {0};
|
||||
struct drm_device *dev = connector->dev;
|
||||
struct drm_display_mode *new_mode;
|
||||
int r, ret = MODE_BAD;
|
||||
int ret;
|
||||
|
||||
drm_display_mode_to_videomode(mode, &vm);
|
||||
mode->vrefresh = drm_mode_vrefresh(mode);
|
||||
drm_mode_copy(adjusted_mode, mode);
|
||||
|
||||
r = priv->dispc_ops->mgr_check_timings(priv->dispc, channel, &vm);
|
||||
if (r)
|
||||
goto done;
|
||||
|
||||
for (dssdev = omap_connector->output; dssdev; dssdev = dssdev->next) {
|
||||
for (; dssdev; dssdev = dssdev->next) {
|
||||
if (!dssdev->ops->check_timings)
|
||||
continue;
|
||||
|
||||
r = dssdev->ops->check_timings(dssdev, &vm);
|
||||
if (r)
|
||||
goto done;
|
||||
ret = dssdev->ops->check_timings(dssdev, adjusted_mode);
|
||||
if (ret)
|
||||
return MODE_BAD;
|
||||
}
|
||||
|
||||
/* check if vrefresh is still valid */
|
||||
new_mode = drm_mode_duplicate(dev, mode);
|
||||
if (!new_mode)
|
||||
return MODE_BAD;
|
||||
return MODE_OK;
|
||||
}
|
||||
|
||||
new_mode->clock = vm.pixelclock / 1000;
|
||||
new_mode->vrefresh = 0;
|
||||
if (mode->vrefresh == drm_mode_vrefresh(new_mode))
|
||||
ret = MODE_OK;
|
||||
drm_mode_destroy(dev, new_mode);
|
||||
static enum drm_mode_status omap_connector_mode_valid(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
struct omap_connector *omap_connector = to_omap_connector(connector);
|
||||
struct drm_display_mode new_mode = { { 0 } };
|
||||
enum drm_mode_status status;
|
||||
|
||||
status = omap_connector_mode_fixup(omap_connector->output, mode,
|
||||
&new_mode);
|
||||
if (status != MODE_OK)
|
||||
goto done;
|
||||
|
||||
/* Check if vrefresh is still valid. */
|
||||
if (drm_mode_vrefresh(mode) != drm_mode_vrefresh(&new_mode))
|
||||
status = MODE_NOCLOCK;
|
||||
|
||||
done:
|
||||
DBG("connector: mode %s: " DRM_MODE_FMT,
|
||||
(ret == MODE_OK) ? "valid" : "invalid",
|
||||
(status == MODE_OK) ? "valid" : "invalid",
|
||||
DRM_MODE_ARG(mode));
|
||||
|
||||
return ret;
|
||||
return status;
|
||||
}
|
||||
|
||||
static const struct drm_connector_funcs omap_connector_funcs = {
|
||||
|
@ -326,9 +308,16 @@ static const struct drm_connector_helper_funcs omap_connector_helper_funcs = {
|
|||
.mode_valid = omap_connector_mode_valid,
|
||||
};
|
||||
|
||||
static int omap_connector_get_type(struct omap_dss_device *display)
|
||||
static int omap_connector_get_type(struct omap_dss_device *output)
|
||||
{
|
||||
switch (display->type) {
|
||||
struct omap_dss_device *display;
|
||||
enum omap_display_type type;
|
||||
|
||||
display = omapdss_display_get(output);
|
||||
type = display->type;
|
||||
omapdss_device_put(display);
|
||||
|
||||
switch (type) {
|
||||
case OMAP_DISPLAY_TYPE_HDMI:
|
||||
return DRM_MODE_CONNECTOR_HDMIA;
|
||||
case OMAP_DISPLAY_TYPE_DVI:
|
||||
|
@ -351,28 +340,26 @@ static int omap_connector_get_type(struct omap_dss_device *display)
|
|||
/* initialize connector */
|
||||
struct drm_connector *omap_connector_init(struct drm_device *dev,
|
||||
struct omap_dss_device *output,
|
||||
struct omap_dss_device *display,
|
||||
struct drm_encoder *encoder)
|
||||
{
|
||||
struct drm_connector *connector = NULL;
|
||||
struct omap_connector *omap_connector;
|
||||
struct omap_dss_device *dssdev;
|
||||
|
||||
DBG("%s", display->name);
|
||||
DBG("%s", output->name);
|
||||
|
||||
omap_connector = kzalloc(sizeof(*omap_connector), GFP_KERNEL);
|
||||
if (!omap_connector)
|
||||
goto fail;
|
||||
|
||||
omap_connector->output = omapdss_device_get(output);
|
||||
omap_connector->display = omapdss_device_get(display);
|
||||
|
||||
connector = &omap_connector->base;
|
||||
connector->interlace_allowed = 1;
|
||||
connector->doublescan_allowed = 0;
|
||||
|
||||
drm_connector_init(dev, connector, &omap_connector_funcs,
|
||||
omap_connector_get_type(display));
|
||||
omap_connector_get_type(output));
|
||||
drm_connector_helper_add(connector, &omap_connector_helper_funcs);
|
||||
|
||||
/*
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
|
||||
#include <linux/types.h>
|
||||
|
||||
enum drm_mode_status;
|
||||
|
||||
struct drm_connector;
|
||||
struct drm_device;
|
||||
struct drm_encoder;
|
||||
|
@ -29,12 +31,12 @@ struct omap_dss_device;
|
|||
|
||||
struct drm_connector *omap_connector_init(struct drm_device *dev,
|
||||
struct omap_dss_device *output,
|
||||
struct omap_dss_device *display,
|
||||
struct drm_encoder *encoder);
|
||||
struct drm_encoder *omap_connector_attached_encoder(
|
||||
struct drm_connector *connector);
|
||||
bool omap_connector_get_hdmi_mode(struct drm_connector *connector);
|
||||
void omap_connector_enable_hpd(struct drm_connector *connector);
|
||||
void omap_connector_disable_hpd(struct drm_connector *connector);
|
||||
enum drm_mode_status omap_connector_mode_fixup(struct omap_dss_device *dssdev,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode);
|
||||
|
||||
#endif /* __OMAPDRM_CONNECTOR_H__ */
|
||||
|
|
|
@ -128,7 +128,7 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable)
|
|||
if (WARN_ON(omap_crtc->enabled == enable))
|
||||
return;
|
||||
|
||||
if (omap_crtc->pipe->output->output_type == OMAP_DISPLAY_TYPE_HDMI) {
|
||||
if (omap_crtc->pipe->output->type == OMAP_DISPLAY_TYPE_HDMI) {
|
||||
priv->dispc_ops->mgr_enable(priv->dispc, channel, enable);
|
||||
omap_crtc->enabled = enable;
|
||||
return;
|
||||
|
@ -390,6 +390,15 @@ static enum drm_mode_status omap_crtc_mode_valid(struct drm_crtc *crtc,
|
|||
const struct drm_display_mode *mode)
|
||||
{
|
||||
struct omap_drm_private *priv = crtc->dev->dev_private;
|
||||
struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
|
||||
struct videomode vm = {0};
|
||||
int r;
|
||||
|
||||
drm_display_mode_to_videomode(mode, &vm);
|
||||
r = priv->dispc_ops->mgr_check_timings(priv->dispc, omap_crtc->channel,
|
||||
&vm);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
/* Check for bandwidth limit */
|
||||
if (priv->max_bandwidth) {
|
||||
|
@ -657,7 +666,7 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
|
|||
&omap_crtc_funcs, NULL);
|
||||
if (ret < 0) {
|
||||
dev_err(dev->dev, "%s(): could not init crtc for: %s\n",
|
||||
__func__, pipe->display->name);
|
||||
__func__, pipe->output->name);
|
||||
kfree(omap_crtc);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <drm/drm_atomic_helper.h>
|
||||
#include <drm/drm_fb_helper.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
#include <drm/drm_panel.h>
|
||||
|
||||
#include "omap_dmm_tiler.h"
|
||||
#include "omap_drv.h"
|
||||
|
@ -137,12 +138,13 @@ static void omap_disconnect_pipelines(struct drm_device *ddev)
|
|||
for (i = 0; i < priv->num_pipes; i++) {
|
||||
struct omap_drm_pipeline *pipe = &priv->pipes[i];
|
||||
|
||||
if (pipe->output->panel)
|
||||
drm_panel_detach(pipe->output->panel);
|
||||
|
||||
omapdss_device_disconnect(NULL, pipe->output);
|
||||
|
||||
omapdss_device_put(pipe->output);
|
||||
omapdss_device_put(pipe->display);
|
||||
pipe->output = NULL;
|
||||
pipe->display = NULL;
|
||||
}
|
||||
|
||||
memset(&priv->channels, 0, sizeof(priv->channels));
|
||||
|
@ -150,33 +152,17 @@ static void omap_disconnect_pipelines(struct drm_device *ddev)
|
|||
priv->num_pipes = 0;
|
||||
}
|
||||
|
||||
static int omap_compare_pipes(const void *a, const void *b)
|
||||
{
|
||||
const struct omap_drm_pipeline *pipe1 = a;
|
||||
const struct omap_drm_pipeline *pipe2 = b;
|
||||
|
||||
if (pipe1->display->alias_id > pipe2->display->alias_id)
|
||||
return 1;
|
||||
else if (pipe1->display->alias_id < pipe2->display->alias_id)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omap_connect_pipelines(struct drm_device *ddev)
|
||||
{
|
||||
struct omap_drm_private *priv = ddev->dev_private;
|
||||
struct omap_dss_device *output = NULL;
|
||||
unsigned int i;
|
||||
int r;
|
||||
|
||||
if (!omapdss_stack_is_ready())
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
for_each_dss_output(output) {
|
||||
r = omapdss_device_connect(priv->dss, NULL, output);
|
||||
if (r == -EPROBE_DEFER) {
|
||||
omapdss_device_put(output);
|
||||
goto cleanup;
|
||||
return r;
|
||||
} else if (r) {
|
||||
dev_warn(output->dev, "could not connect output %s\n",
|
||||
output->name);
|
||||
|
@ -185,7 +171,6 @@ static int omap_connect_pipelines(struct drm_device *ddev)
|
|||
|
||||
pipe = &priv->pipes[priv->num_pipes++];
|
||||
pipe->output = omapdss_device_get(output);
|
||||
pipe->display = omapdss_display_get(output);
|
||||
|
||||
if (priv->num_pipes == ARRAY_SIZE(priv->pipes)) {
|
||||
/* To balance the 'for_each_dss_output' loop */
|
||||
|
@ -195,36 +180,19 @@ static int omap_connect_pipelines(struct drm_device *ddev)
|
|||
}
|
||||
}
|
||||
|
||||
/* Sort the list by DT aliases */
|
||||
sort(priv->pipes, priv->num_pipes, sizeof(priv->pipes[0]),
|
||||
omap_compare_pipes, NULL);
|
||||
|
||||
/*
|
||||
* Populate the pipeline lookup table by DISPC channel. Only one display
|
||||
* is allowed per channel.
|
||||
*/
|
||||
for (i = 0; i < priv->num_pipes; ++i) {
|
||||
struct omap_drm_pipeline *pipe = &priv->pipes[i];
|
||||
enum omap_channel channel = pipe->output->dispc_channel;
|
||||
|
||||
if (WARN_ON(priv->channels[channel] != NULL)) {
|
||||
r = -EINVAL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
priv->channels[channel] = pipe;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
/*
|
||||
* if we are deferring probe, we disconnect the devices we previously
|
||||
* connected
|
||||
*/
|
||||
omap_disconnect_pipelines(ddev);
|
||||
static int omap_compare_pipelines(const void *a, const void *b)
|
||||
{
|
||||
const struct omap_drm_pipeline *pipe1 = a;
|
||||
const struct omap_drm_pipeline *pipe2 = b;
|
||||
|
||||
return r;
|
||||
if (pipe1->alias_id > pipe2->alias_id)
|
||||
return 1;
|
||||
else if (pipe1->alias_id < pipe2->alias_id)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omap_modeset_init_properties(struct drm_device *dev)
|
||||
|
@ -240,6 +208,30 @@ static int omap_modeset_init_properties(struct drm_device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int omap_display_id(struct omap_dss_device *output)
|
||||
{
|
||||
struct device_node *node = NULL;
|
||||
|
||||
if (output->next) {
|
||||
struct omap_dss_device *display;
|
||||
|
||||
display = omapdss_display_get(output);
|
||||
node = display->dev->of_node;
|
||||
omapdss_device_put(display);
|
||||
} else if (output->bridge) {
|
||||
struct drm_bridge *bridge = output->bridge;
|
||||
|
||||
while (bridge->next)
|
||||
bridge = bridge->next;
|
||||
|
||||
node = bridge->of_node;
|
||||
} else if (output->panel) {
|
||||
node = output->panel->dev->of_node;
|
||||
}
|
||||
|
||||
return node ? of_alias_get_id(node, "display") : -ENODEV;
|
||||
}
|
||||
|
||||
static int omap_modeset_init(struct drm_device *dev)
|
||||
{
|
||||
struct omap_drm_private *priv = dev->dev_private;
|
||||
|
@ -249,6 +241,9 @@ static int omap_modeset_init(struct drm_device *dev)
|
|||
int ret;
|
||||
u32 plane_crtc_mask;
|
||||
|
||||
if (!omapdss_stack_is_ready())
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
drm_mode_config_init(dev);
|
||||
|
||||
ret = omap_modeset_init_properties(dev);
|
||||
|
@ -263,6 +258,10 @@ static int omap_modeset_init(struct drm_device *dev)
|
|||
* configuration does not match the expectations or exceeds
|
||||
* the available resources, the configuration is rejected.
|
||||
*/
|
||||
ret = omap_connect_pipelines(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (priv->num_pipes > num_mgrs || priv->num_pipes > num_ovls) {
|
||||
dev_err(dev->dev, "%s(): Too many connected displays\n",
|
||||
__func__);
|
||||
|
@ -288,33 +287,75 @@ static int omap_modeset_init(struct drm_device *dev)
|
|||
priv->planes[priv->num_planes++] = plane;
|
||||
}
|
||||
|
||||
/* Create the CRTCs, encoders and connectors. */
|
||||
/*
|
||||
* Create the encoders, attach the bridges and get the pipeline alias
|
||||
* IDs.
|
||||
*/
|
||||
for (i = 0; i < priv->num_pipes; i++) {
|
||||
struct omap_drm_pipeline *pipe = &priv->pipes[i];
|
||||
struct omap_dss_device *display = pipe->display;
|
||||
struct drm_connector *connector;
|
||||
struct drm_encoder *encoder;
|
||||
int id;
|
||||
|
||||
pipe->encoder = omap_encoder_init(dev, pipe->output);
|
||||
if (!pipe->encoder)
|
||||
return -ENOMEM;
|
||||
|
||||
if (pipe->output->bridge) {
|
||||
ret = drm_bridge_attach(pipe->encoder,
|
||||
pipe->output->bridge, NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
id = omap_display_id(pipe->output);
|
||||
pipe->alias_id = id >= 0 ? id : i;
|
||||
}
|
||||
|
||||
/* Sort the pipelines by DT aliases. */
|
||||
sort(priv->pipes, priv->num_pipes, sizeof(priv->pipes[0]),
|
||||
omap_compare_pipelines, NULL);
|
||||
|
||||
/*
|
||||
* Populate the pipeline lookup table by DISPC channel. Only one display
|
||||
* is allowed per channel.
|
||||
*/
|
||||
for (i = 0; i < priv->num_pipes; ++i) {
|
||||
struct omap_drm_pipeline *pipe = &priv->pipes[i];
|
||||
enum omap_channel channel = pipe->output->dispc_channel;
|
||||
|
||||
if (WARN_ON(priv->channels[channel] != NULL))
|
||||
return -EINVAL;
|
||||
|
||||
priv->channels[channel] = pipe;
|
||||
}
|
||||
|
||||
/* Create the connectors and CRTCs. */
|
||||
for (i = 0; i < priv->num_pipes; i++) {
|
||||
struct omap_drm_pipeline *pipe = &priv->pipes[i];
|
||||
struct drm_encoder *encoder = pipe->encoder;
|
||||
struct drm_crtc *crtc;
|
||||
|
||||
encoder = omap_encoder_init(dev, pipe->output, display);
|
||||
if (!encoder)
|
||||
return -ENOMEM;
|
||||
if (!pipe->output->bridge) {
|
||||
pipe->connector = omap_connector_init(dev, pipe->output,
|
||||
encoder);
|
||||
if (!pipe->connector)
|
||||
return -ENOMEM;
|
||||
|
||||
connector = omap_connector_init(dev, pipe->output, display,
|
||||
encoder);
|
||||
if (!connector)
|
||||
return -ENOMEM;
|
||||
drm_connector_attach_encoder(pipe->connector, encoder);
|
||||
|
||||
if (pipe->output->panel) {
|
||||
ret = drm_panel_attach(pipe->output->panel,
|
||||
pipe->connector);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
crtc = omap_crtc_init(dev, pipe, priv->planes[i]);
|
||||
if (IS_ERR(crtc))
|
||||
return PTR_ERR(crtc);
|
||||
|
||||
drm_connector_attach_encoder(connector, encoder);
|
||||
encoder->possible_crtcs = 1 << i;
|
||||
|
||||
pipe->crtc = crtc;
|
||||
pipe->encoder = encoder;
|
||||
pipe->connector = connector;
|
||||
}
|
||||
|
||||
DBG("registered %u planes, %u crtcs/encoders/connectors\n",
|
||||
|
@ -351,10 +392,12 @@ static int omap_modeset_init(struct drm_device *dev)
|
|||
static void omap_modeset_enable_external_hpd(struct drm_device *ddev)
|
||||
{
|
||||
struct omap_drm_private *priv = ddev->dev_private;
|
||||
int i;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < priv->num_pipes; i++)
|
||||
omap_connector_enable_hpd(priv->pipes[i].connector);
|
||||
for (i = 0; i < priv->num_pipes; i++) {
|
||||
if (priv->pipes[i].connector)
|
||||
omap_connector_enable_hpd(priv->pipes[i].connector);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -363,10 +406,12 @@ static void omap_modeset_enable_external_hpd(struct drm_device *ddev)
|
|||
static void omap_modeset_disable_external_hpd(struct drm_device *ddev)
|
||||
{
|
||||
struct omap_drm_private *priv = ddev->dev_private;
|
||||
int i;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < priv->num_pipes; i++)
|
||||
omap_connector_disable_hpd(priv->pipes[i].connector);
|
||||
for (i = 0; i < priv->num_pipes; i++) {
|
||||
if (priv->pipes[i].connector)
|
||||
omap_connector_disable_hpd(priv->pipes[i].connector);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -551,10 +596,6 @@ static int omapdrm_init(struct omap_drm_private *priv, struct device *dev)
|
|||
|
||||
omap_crtc_pre_init(priv);
|
||||
|
||||
ret = omap_connect_pipelines(ddev);
|
||||
if (ret)
|
||||
goto err_crtc_uninit;
|
||||
|
||||
soc = soc_device_match(omapdrm_soc_devices);
|
||||
priv->omaprev = soc ? (unsigned int)soc->data : 0;
|
||||
priv->wq = alloc_ordered_workqueue("omapdrm", 0);
|
||||
|
@ -612,7 +653,6 @@ err_gem_deinit:
|
|||
omap_gem_deinit(ddev);
|
||||
destroy_workqueue(priv->wq);
|
||||
omap_disconnect_pipelines(ddev);
|
||||
err_crtc_uninit:
|
||||
omap_crtc_pre_uninit(priv);
|
||||
drm_dev_put(ddev);
|
||||
return ret;
|
||||
|
@ -685,54 +725,12 @@ static int pdev_remove(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int omap_drm_suspend_all_displays(struct drm_device *ddev)
|
||||
{
|
||||
struct omap_drm_private *priv = ddev->dev_private;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < priv->num_pipes; i++) {
|
||||
struct omap_dss_device *display = priv->pipes[i].display;
|
||||
|
||||
if (display->state == OMAP_DSS_DISPLAY_ACTIVE) {
|
||||
display->ops->disable(display);
|
||||
display->activate_after_resume = true;
|
||||
} else {
|
||||
display->activate_after_resume = false;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omap_drm_resume_all_displays(struct drm_device *ddev)
|
||||
{
|
||||
struct omap_drm_private *priv = ddev->dev_private;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < priv->num_pipes; i++) {
|
||||
struct omap_dss_device *display = priv->pipes[i].display;
|
||||
|
||||
if (display->activate_after_resume) {
|
||||
display->ops->enable(display);
|
||||
display->activate_after_resume = false;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omap_drm_suspend(struct device *dev)
|
||||
{
|
||||
struct omap_drm_private *priv = dev_get_drvdata(dev);
|
||||
struct drm_device *drm_dev = priv->ddev;
|
||||
|
||||
drm_kms_helper_poll_disable(drm_dev);
|
||||
|
||||
drm_modeset_lock_all(drm_dev);
|
||||
omap_drm_suspend_all_displays(drm_dev);
|
||||
drm_modeset_unlock_all(drm_dev);
|
||||
|
||||
return 0;
|
||||
return drm_mode_config_helper_suspend(drm_dev);
|
||||
}
|
||||
|
||||
static int omap_drm_resume(struct device *dev)
|
||||
|
@ -740,11 +738,7 @@ static int omap_drm_resume(struct device *dev)
|
|||
struct omap_drm_private *priv = dev_get_drvdata(dev);
|
||||
struct drm_device *drm_dev = priv->ddev;
|
||||
|
||||
drm_modeset_lock_all(drm_dev);
|
||||
omap_drm_resume_all_displays(drm_dev);
|
||||
drm_modeset_unlock_all(drm_dev);
|
||||
|
||||
drm_kms_helper_poll_enable(drm_dev);
|
||||
drm_mode_config_helper_resume(drm_dev);
|
||||
|
||||
return omap_gem_resume(drm_dev);
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ struct omap_drm_pipeline {
|
|||
struct drm_encoder *encoder;
|
||||
struct drm_connector *connector;
|
||||
struct omap_dss_device *output;
|
||||
struct omap_dss_device *display;
|
||||
unsigned int alias_id;
|
||||
};
|
||||
|
||||
struct omap_drm_private {
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_modeset_helper_vtables.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <drm/drm_panel.h>
|
||||
|
||||
#include "omap_drv.h"
|
||||
|
||||
|
@ -37,7 +38,6 @@
|
|||
struct omap_encoder {
|
||||
struct drm_encoder base;
|
||||
struct omap_dss_device *output;
|
||||
struct omap_dss_device *display;
|
||||
};
|
||||
|
||||
static void omap_encoder_destroy(struct drm_encoder *encoder)
|
||||
|
@ -52,22 +52,43 @@ static const struct drm_encoder_funcs omap_encoder_funcs = {
|
|||
.destroy = omap_encoder_destroy,
|
||||
};
|
||||
|
||||
static void omap_encoder_hdmi_mode_set(struct drm_encoder *encoder,
|
||||
static void omap_encoder_update_videomode_flags(struct videomode *vm,
|
||||
u32 bus_flags)
|
||||
{
|
||||
if (!(vm->flags & (DISPLAY_FLAGS_DE_LOW |
|
||||
DISPLAY_FLAGS_DE_HIGH))) {
|
||||
if (bus_flags & DRM_BUS_FLAG_DE_LOW)
|
||||
vm->flags |= DISPLAY_FLAGS_DE_LOW;
|
||||
else if (bus_flags & DRM_BUS_FLAG_DE_HIGH)
|
||||
vm->flags |= DISPLAY_FLAGS_DE_HIGH;
|
||||
}
|
||||
|
||||
if (!(vm->flags & (DISPLAY_FLAGS_PIXDATA_POSEDGE |
|
||||
DISPLAY_FLAGS_PIXDATA_NEGEDGE))) {
|
||||
if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE)
|
||||
vm->flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE;
|
||||
else if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)
|
||||
vm->flags |= DISPLAY_FLAGS_PIXDATA_NEGEDGE;
|
||||
}
|
||||
|
||||
if (!(vm->flags & (DISPLAY_FLAGS_SYNC_POSEDGE |
|
||||
DISPLAY_FLAGS_SYNC_NEGEDGE))) {
|
||||
if (bus_flags & DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE)
|
||||
vm->flags |= DISPLAY_FLAGS_SYNC_POSEDGE;
|
||||
else if (bus_flags & DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE)
|
||||
vm->flags |= DISPLAY_FLAGS_SYNC_NEGEDGE;
|
||||
}
|
||||
}
|
||||
|
||||
static void omap_encoder_hdmi_mode_set(struct drm_connector *connector,
|
||||
struct drm_encoder *encoder,
|
||||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
|
||||
struct omap_dss_device *dssdev = omap_encoder->output;
|
||||
struct drm_connector *connector;
|
||||
bool hdmi_mode;
|
||||
|
||||
hdmi_mode = false;
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||
if (connector->encoder == encoder) {
|
||||
hdmi_mode = omap_connector_get_hdmi_mode(connector);
|
||||
break;
|
||||
}
|
||||
}
|
||||
hdmi_mode = omap_connector_get_hdmi_mode(connector);
|
||||
|
||||
if (dssdev->ops->hdmi.set_hdmi_mode)
|
||||
dssdev->ops->hdmi.set_hdmi_mode(dssdev, hdmi_mode);
|
||||
|
@ -88,8 +109,18 @@ static void omap_encoder_mode_set(struct drm_encoder *encoder,
|
|||
struct drm_display_mode *adjusted_mode)
|
||||
{
|
||||
struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
|
||||
struct omap_dss_device *output = omap_encoder->output;
|
||||
struct omap_dss_device *dssdev;
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct drm_connector *connector;
|
||||
struct drm_bridge *bridge;
|
||||
struct videomode vm = { 0 };
|
||||
u32 bus_flags;
|
||||
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||
if (connector->encoder == encoder)
|
||||
break;
|
||||
}
|
||||
|
||||
drm_display_mode_to_videomode(adjusted_mode, &vm);
|
||||
|
||||
|
@ -102,66 +133,102 @@ static void omap_encoder_mode_set(struct drm_encoder *encoder,
|
|||
*
|
||||
* A better solution is to use DRM's bus-flags through the whole driver.
|
||||
*/
|
||||
for (dssdev = omap_encoder->output; dssdev; dssdev = dssdev->next) {
|
||||
unsigned long bus_flags = dssdev->bus_flags;
|
||||
for (dssdev = output; dssdev; dssdev = dssdev->next)
|
||||
omap_encoder_update_videomode_flags(&vm, dssdev->bus_flags);
|
||||
|
||||
if (!(vm.flags & (DISPLAY_FLAGS_DE_LOW |
|
||||
DISPLAY_FLAGS_DE_HIGH))) {
|
||||
if (bus_flags & DRM_BUS_FLAG_DE_LOW)
|
||||
vm.flags |= DISPLAY_FLAGS_DE_LOW;
|
||||
else if (bus_flags & DRM_BUS_FLAG_DE_HIGH)
|
||||
vm.flags |= DISPLAY_FLAGS_DE_HIGH;
|
||||
}
|
||||
for (bridge = output->bridge; bridge; bridge = bridge->next) {
|
||||
if (!bridge->timings)
|
||||
continue;
|
||||
|
||||
if (!(vm.flags & (DISPLAY_FLAGS_PIXDATA_POSEDGE |
|
||||
DISPLAY_FLAGS_PIXDATA_NEGEDGE))) {
|
||||
if (bus_flags & DRM_BUS_FLAG_PIXDATA_POSEDGE)
|
||||
vm.flags |= DISPLAY_FLAGS_PIXDATA_POSEDGE;
|
||||
else if (bus_flags & DRM_BUS_FLAG_PIXDATA_NEGEDGE)
|
||||
vm.flags |= DISPLAY_FLAGS_PIXDATA_NEGEDGE;
|
||||
}
|
||||
|
||||
if (!(vm.flags & (DISPLAY_FLAGS_SYNC_POSEDGE |
|
||||
DISPLAY_FLAGS_SYNC_NEGEDGE))) {
|
||||
if (bus_flags & DRM_BUS_FLAG_SYNC_POSEDGE)
|
||||
vm.flags |= DISPLAY_FLAGS_SYNC_POSEDGE;
|
||||
else if (bus_flags & DRM_BUS_FLAG_SYNC_NEGEDGE)
|
||||
vm.flags |= DISPLAY_FLAGS_SYNC_NEGEDGE;
|
||||
}
|
||||
bus_flags = bridge->timings->input_bus_flags;
|
||||
omap_encoder_update_videomode_flags(&vm, bus_flags);
|
||||
}
|
||||
|
||||
/* Set timings for all devices in the display pipeline. */
|
||||
dss_mgr_set_timings(omap_encoder->output, &vm);
|
||||
bus_flags = connector->display_info.bus_flags;
|
||||
omap_encoder_update_videomode_flags(&vm, bus_flags);
|
||||
|
||||
for (dssdev = omap_encoder->output; dssdev; dssdev = dssdev->next) {
|
||||
/* Set timings for all devices in the display pipeline. */
|
||||
dss_mgr_set_timings(output, &vm);
|
||||
|
||||
for (dssdev = output; dssdev; dssdev = dssdev->next) {
|
||||
if (dssdev->ops->set_timings)
|
||||
dssdev->ops->set_timings(dssdev, &vm);
|
||||
dssdev->ops->set_timings(dssdev, adjusted_mode);
|
||||
}
|
||||
|
||||
/* Set the HDMI mode and HDMI infoframe if applicable. */
|
||||
if (omap_encoder->output->output_type == OMAP_DISPLAY_TYPE_HDMI)
|
||||
omap_encoder_hdmi_mode_set(encoder, adjusted_mode);
|
||||
if (output->type == OMAP_DISPLAY_TYPE_HDMI)
|
||||
omap_encoder_hdmi_mode_set(connector, encoder, adjusted_mode);
|
||||
}
|
||||
|
||||
static void omap_encoder_disable(struct drm_encoder *encoder)
|
||||
{
|
||||
struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
|
||||
struct omap_dss_device *dssdev = omap_encoder->display;
|
||||
struct omap_dss_device *dssdev = omap_encoder->output;
|
||||
struct drm_device *dev = encoder->dev;
|
||||
|
||||
dssdev->ops->disable(dssdev);
|
||||
dev_dbg(dev->dev, "disable(%s)\n", dssdev->name);
|
||||
|
||||
/* Disable the panel if present. */
|
||||
if (dssdev->panel) {
|
||||
drm_panel_disable(dssdev->panel);
|
||||
drm_panel_unprepare(dssdev->panel);
|
||||
}
|
||||
|
||||
/*
|
||||
* Disable the chain of external devices, starting at the one at the
|
||||
* internal encoder's output.
|
||||
*/
|
||||
omapdss_device_disable(dssdev->next);
|
||||
|
||||
/*
|
||||
* Disable the internal encoder. This will disable the DSS output. The
|
||||
* DSI is treated as an exception as DSI pipelines still use the legacy
|
||||
* flow where the pipeline output controls the encoder.
|
||||
*/
|
||||
if (dssdev->type != OMAP_DISPLAY_TYPE_DSI) {
|
||||
dssdev->ops->disable(dssdev);
|
||||
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform the post-disable operations on the chain of external devices
|
||||
* to complete the display pipeline disable.
|
||||
*/
|
||||
omapdss_device_post_disable(dssdev->next);
|
||||
}
|
||||
|
||||
static void omap_encoder_enable(struct drm_encoder *encoder)
|
||||
{
|
||||
struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
|
||||
struct omap_dss_device *dssdev = omap_encoder->display;
|
||||
int r;
|
||||
struct omap_dss_device *dssdev = omap_encoder->output;
|
||||
struct drm_device *dev = encoder->dev;
|
||||
|
||||
r = dssdev->ops->enable(dssdev);
|
||||
if (r)
|
||||
dev_err(encoder->dev->dev,
|
||||
"Failed to enable display '%s': %d\n",
|
||||
dssdev->name, r);
|
||||
dev_dbg(dev->dev, "enable(%s)\n", dssdev->name);
|
||||
|
||||
/* Prepare the chain of external devices for pipeline enable. */
|
||||
omapdss_device_pre_enable(dssdev->next);
|
||||
|
||||
/*
|
||||
* Enable the internal encoder. This will enable the DSS output. The
|
||||
* DSI is treated as an exception as DSI pipelines still use the legacy
|
||||
* flow where the pipeline output controls the encoder.
|
||||
*/
|
||||
if (dssdev->type != OMAP_DISPLAY_TYPE_DSI) {
|
||||
dssdev->ops->enable(dssdev);
|
||||
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable the chain of external devices, starting at the one at the
|
||||
* internal encoder's output.
|
||||
*/
|
||||
omapdss_device_enable(dssdev->next);
|
||||
|
||||
/* Enable the panel if present. */
|
||||
if (dssdev->panel) {
|
||||
drm_panel_prepare(dssdev->panel);
|
||||
drm_panel_enable(dssdev->panel);
|
||||
}
|
||||
}
|
||||
|
||||
static int omap_encoder_atomic_check(struct drm_encoder *encoder,
|
||||
|
@ -169,35 +236,17 @@ static int omap_encoder_atomic_check(struct drm_encoder *encoder,
|
|||
struct drm_connector_state *conn_state)
|
||||
{
|
||||
struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
|
||||
enum omap_channel channel = omap_encoder->output->dispc_channel;
|
||||
struct drm_device *dev = encoder->dev;
|
||||
struct omap_drm_private *priv = dev->dev_private;
|
||||
struct omap_dss_device *dssdev;
|
||||
struct videomode vm = { 0 };
|
||||
int ret;
|
||||
enum drm_mode_status status;
|
||||
|
||||
drm_display_mode_to_videomode(&crtc_state->mode, &vm);
|
||||
|
||||
ret = priv->dispc_ops->mgr_check_timings(priv->dispc, channel, &vm);
|
||||
if (ret)
|
||||
goto done;
|
||||
|
||||
for (dssdev = omap_encoder->output; dssdev; dssdev = dssdev->next) {
|
||||
if (!dssdev->ops->check_timings)
|
||||
continue;
|
||||
|
||||
ret = dssdev->ops->check_timings(dssdev, &vm);
|
||||
if (ret)
|
||||
goto done;
|
||||
status = omap_connector_mode_fixup(omap_encoder->output,
|
||||
&crtc_state->mode,
|
||||
&crtc_state->adjusted_mode);
|
||||
if (status != MODE_OK) {
|
||||
dev_err(encoder->dev->dev, "invalid timings: %d\n", status);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
drm_display_mode_from_videomode(&vm, &crtc_state->adjusted_mode);
|
||||
|
||||
done:
|
||||
if (ret)
|
||||
dev_err(dev->dev, "invalid timings: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct drm_encoder_helper_funcs omap_encoder_helper_funcs = {
|
||||
|
@ -209,8 +258,7 @@ static const struct drm_encoder_helper_funcs omap_encoder_helper_funcs = {
|
|||
|
||||
/* initialize encoder */
|
||||
struct drm_encoder *omap_encoder_init(struct drm_device *dev,
|
||||
struct omap_dss_device *output,
|
||||
struct omap_dss_device *display)
|
||||
struct omap_dss_device *output)
|
||||
{
|
||||
struct drm_encoder *encoder = NULL;
|
||||
struct omap_encoder *omap_encoder;
|
||||
|
@ -220,7 +268,6 @@ struct drm_encoder *omap_encoder_init(struct drm_device *dev,
|
|||
goto fail;
|
||||
|
||||
omap_encoder->output = output;
|
||||
omap_encoder->display = display;
|
||||
|
||||
encoder = &omap_encoder->base;
|
||||
|
||||
|
|
|
@ -25,7 +25,6 @@ struct drm_encoder;
|
|||
struct omap_dss_device;
|
||||
|
||||
struct drm_encoder *omap_encoder_init(struct drm_device *dev,
|
||||
struct omap_dss_device *output,
|
||||
struct omap_dss_device *display);
|
||||
struct omap_dss_device *output);
|
||||
|
||||
#endif /* __OMAPDRM_ENCODER_H__ */
|
||||
|
|
|
@ -191,7 +191,7 @@ static const struct versatile_panel_type versatile_panels[] = {
|
|||
.vrefresh = 390,
|
||||
.flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC,
|
||||
},
|
||||
.bus_flags = DRM_BUS_FLAG_PIXDATA_NEGEDGE,
|
||||
.bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE,
|
||||
},
|
||||
/*
|
||||
* Sanyo ALR252RGT 240x320 portrait display found on the
|
||||
|
@ -215,7 +215,7 @@ static const struct versatile_panel_type versatile_panels[] = {
|
|||
.vrefresh = 116,
|
||||
.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
|
||||
},
|
||||
.bus_flags = DRM_BUS_FLAG_PIXDATA_NEGEDGE,
|
||||
.bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE,
|
||||
.ib2 = true,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -412,11 +412,11 @@ static int ili9322_init(struct drm_panel *panel, struct ili9322 *ili)
|
|||
if (ili->conf->dclk_active_high) {
|
||||
reg = ILI9322_POL_DCLK;
|
||||
connector->display_info.bus_flags |=
|
||||
DRM_BUS_FLAG_PIXDATA_POSEDGE;
|
||||
DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE;
|
||||
} else {
|
||||
reg = 0;
|
||||
connector->display_info.bus_flags |=
|
||||
DRM_BUS_FLAG_PIXDATA_NEGEDGE;
|
||||
DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE;
|
||||
}
|
||||
if (ili->conf->de_active_high) {
|
||||
reg |= ILI9322_POL_DE;
|
||||
|
|
|
@ -328,7 +328,7 @@ static const struct seiko_panel_desc seiko_43wvf1g = {
|
|||
.height = 57,
|
||||
},
|
||||
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
|
||||
.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_NEGEDGE,
|
||||
.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE,
|
||||
};
|
||||
|
||||
static const struct of_device_id platform_of_match[] = {
|
||||
|
|
|
@ -914,7 +914,7 @@ static const struct panel_desc cdtech_s043wq26h_ct7 = {
|
|||
.width = 95,
|
||||
.height = 54,
|
||||
},
|
||||
.bus_flags = DRM_BUS_FLAG_PIXDATA_POSEDGE,
|
||||
.bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE,
|
||||
};
|
||||
|
||||
static const struct drm_display_mode cdtech_s070wv95_ct16_mode = {
|
||||
|
@ -1034,7 +1034,7 @@ static const struct panel_desc dataimage_scf0700c48ggu18 = {
|
|||
.height = 91,
|
||||
},
|
||||
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
|
||||
.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_POSEDGE,
|
||||
.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE,
|
||||
};
|
||||
|
||||
static const struct display_timing dlc_dlc0700yzg_1_timing = {
|
||||
|
@ -1119,7 +1119,7 @@ static const struct panel_desc edt_et057090dhu = {
|
|||
.height = 86,
|
||||
},
|
||||
.bus_format = MEDIA_BUS_FMT_RGB666_1X18,
|
||||
.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_NEGEDGE,
|
||||
.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE,
|
||||
};
|
||||
|
||||
static const struct drm_display_mode edt_etm0700g0dh6_mode = {
|
||||
|
@ -1145,7 +1145,7 @@ static const struct panel_desc edt_etm0700g0dh6 = {
|
|||
.height = 91,
|
||||
},
|
||||
.bus_format = MEDIA_BUS_FMT_RGB666_1X18,
|
||||
.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_NEGEDGE,
|
||||
.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE,
|
||||
};
|
||||
|
||||
static const struct panel_desc edt_etm0700g0bdh6 = {
|
||||
|
@ -1157,7 +1157,7 @@ static const struct panel_desc edt_etm0700g0bdh6 = {
|
|||
.height = 91,
|
||||
},
|
||||
.bus_format = MEDIA_BUS_FMT_RGB666_1X18,
|
||||
.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_POSEDGE,
|
||||
.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE,
|
||||
};
|
||||
|
||||
static const struct drm_display_mode foxlink_fl500wvr00_a0t_mode = {
|
||||
|
@ -1311,7 +1311,7 @@ static const struct panel_desc innolux_at043tn24 = {
|
|||
.height = 54,
|
||||
},
|
||||
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
|
||||
.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_POSEDGE,
|
||||
.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE,
|
||||
};
|
||||
|
||||
static const struct drm_display_mode innolux_at070tn92_mode = {
|
||||
|
@ -1818,7 +1818,7 @@ static const struct panel_desc nec_nl4827hc19_05b = {
|
|||
.height = 54,
|
||||
},
|
||||
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
|
||||
.bus_flags = DRM_BUS_FLAG_PIXDATA_POSEDGE,
|
||||
.bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE,
|
||||
};
|
||||
|
||||
static const struct drm_display_mode netron_dy_e231732_mode = {
|
||||
|
@ -1867,8 +1867,8 @@ static const struct panel_desc newhaven_nhd_43_480272ef_atxl = {
|
|||
.height = 54,
|
||||
},
|
||||
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
|
||||
.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_POSEDGE |
|
||||
DRM_BUS_FLAG_SYNC_POSEDGE,
|
||||
.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE |
|
||||
DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE,
|
||||
};
|
||||
|
||||
static const struct display_timing nlt_nl192108ac18_02d_timing = {
|
||||
|
@ -2029,7 +2029,33 @@ static const struct panel_desc ortustech_com43h4m85ulc = {
|
|||
.height = 93,
|
||||
},
|
||||
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
|
||||
.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_POSEDGE,
|
||||
.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE,
|
||||
};
|
||||
|
||||
static const struct drm_display_mode osddisplays_osd070t1718_19ts_mode = {
|
||||
.clock = 33000,
|
||||
.hdisplay = 800,
|
||||
.hsync_start = 800 + 210,
|
||||
.hsync_end = 800 + 210 + 30,
|
||||
.htotal = 800 + 210 + 30 + 16,
|
||||
.vdisplay = 480,
|
||||
.vsync_start = 480 + 22,
|
||||
.vsync_end = 480 + 22 + 13,
|
||||
.vtotal = 480 + 22 + 13 + 10,
|
||||
.vrefresh = 60,
|
||||
.flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
|
||||
};
|
||||
|
||||
static const struct panel_desc osddisplays_osd070t1718_19ts = {
|
||||
.modes = &osddisplays_osd070t1718_19ts_mode,
|
||||
.num_modes = 1,
|
||||
.bpc = 8,
|
||||
.size = {
|
||||
.width = 152,
|
||||
.height = 91,
|
||||
},
|
||||
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
|
||||
.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE,
|
||||
};
|
||||
|
||||
static const struct drm_display_mode pda_91_00156_a0_mode = {
|
||||
|
@ -2398,7 +2424,7 @@ static const struct panel_desc toshiba_lt089ac29000 = {
|
|||
.height = 116,
|
||||
},
|
||||
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
|
||||
.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_POSEDGE,
|
||||
.bus_flags = DRM_BUS_FLAG_DE_HIGH | DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE,
|
||||
};
|
||||
|
||||
static const struct drm_display_mode tpk_f07a_0102_mode = {
|
||||
|
@ -2421,7 +2447,7 @@ static const struct panel_desc tpk_f07a_0102 = {
|
|||
.width = 152,
|
||||
.height = 91,
|
||||
},
|
||||
.bus_flags = DRM_BUS_FLAG_PIXDATA_POSEDGE,
|
||||
.bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE,
|
||||
};
|
||||
|
||||
static const struct drm_display_mode tpk_f10a_0102_mode = {
|
||||
|
@ -2736,6 +2762,9 @@ static const struct of_device_id platform_of_match[] = {
|
|||
}, {
|
||||
.compatible = "ortustech,com43h4m85ulc",
|
||||
.data = &ortustech_com43h4m85ulc,
|
||||
}, {
|
||||
.compatible = "osddisplays,osd070t1718-19ts",
|
||||
.data = &osddisplays_osd070t1718_19ts,
|
||||
}, {
|
||||
.compatible = "pda,91-00156-a0",
|
||||
.data = &pda_91_00156_a0,
|
||||
|
|
|
@ -118,7 +118,7 @@ static const struct tpg110_panel_mode tpg110_modes[] = {
|
|||
.vtotal = 480 + 10 + 1 + 35,
|
||||
.vrefresh = 60,
|
||||
},
|
||||
.bus_flags = DRM_BUS_FLAG_PIXDATA_POSEDGE,
|
||||
.bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE,
|
||||
},
|
||||
{
|
||||
.name = "640x480 RGB",
|
||||
|
@ -135,7 +135,7 @@ static const struct tpg110_panel_mode tpg110_modes[] = {
|
|||
.vtotal = 480 + 18 + 1 + 27,
|
||||
.vrefresh = 60,
|
||||
},
|
||||
.bus_flags = DRM_BUS_FLAG_PIXDATA_POSEDGE,
|
||||
.bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE,
|
||||
},
|
||||
{
|
||||
.name = "480x272 RGB",
|
||||
|
@ -152,7 +152,7 @@ static const struct tpg110_panel_mode tpg110_modes[] = {
|
|||
.vtotal = 272 + 2 + 1 + 12,
|
||||
.vrefresh = 60,
|
||||
},
|
||||
.bus_flags = DRM_BUS_FLAG_PIXDATA_POSEDGE,
|
||||
.bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE,
|
||||
},
|
||||
{
|
||||
.name = "480x640 RGB",
|
||||
|
@ -169,7 +169,7 @@ static const struct tpg110_panel_mode tpg110_modes[] = {
|
|||
.vtotal = 640 + 4 + 1 + 8,
|
||||
.vrefresh = 60,
|
||||
},
|
||||
.bus_flags = DRM_BUS_FLAG_PIXDATA_POSEDGE,
|
||||
.bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE,
|
||||
},
|
||||
{
|
||||
.name = "400x240 RGB",
|
||||
|
@ -186,7 +186,7 @@ static const struct tpg110_panel_mode tpg110_modes[] = {
|
|||
.vtotal = 240 + 2 + 1 + 20,
|
||||
.vrefresh = 60,
|
||||
},
|
||||
.bus_flags = DRM_BUS_FLAG_PIXDATA_POSEDGE,
|
||||
.bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -188,7 +188,7 @@ static void pl111_display_enable(struct drm_simple_display_pipe *pipe,
|
|||
tim2 |= TIM2_IOE;
|
||||
|
||||
if (connector->display_info.bus_flags &
|
||||
DRM_BUS_FLAG_PIXDATA_NEGEDGE)
|
||||
DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)
|
||||
tim2 |= TIM2_IPC;
|
||||
}
|
||||
|
||||
|
|
|
@ -561,10 +561,10 @@ static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon,
|
|||
* Following code is a way to avoid quirks all around TCON
|
||||
* and DOTCLOCK drivers.
|
||||
*/
|
||||
if (display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_POSEDGE)
|
||||
if (display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE)
|
||||
clk_set_phase(tcon->dclk, 240);
|
||||
|
||||
if (display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_NEGEDGE)
|
||||
if (display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)
|
||||
clk_set_phase(tcon->dclk, 0);
|
||||
|
||||
regmap_update_bits(tcon->regs, SUN4I_TCON0_IO_POL_REG,
|
||||
|
|
|
@ -149,7 +149,8 @@ static void tve200_display_enable(struct drm_simple_display_pipe *pipe,
|
|||
/* Vsync IRQ at start of Vsync at first */
|
||||
ctrl1 |= TVE200_VSTSTYPE_VSYNC;
|
||||
|
||||
if (connector->display_info.bus_flags & DRM_BUS_FLAG_PIXDATA_NEGEDGE)
|
||||
if (connector->display_info.bus_flags &
|
||||
DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)
|
||||
ctrl1 |= TVE200_CTRL_TVCLKP;
|
||||
|
||||
if ((mode->hdisplay == 352 && mode->vdisplay == 240) || /* SIF(525) */
|
||||
|
|
|
@ -244,14 +244,13 @@ struct drm_bridge_funcs {
|
|||
*/
|
||||
struct drm_bridge_timings {
|
||||
/**
|
||||
* @sampling_edge:
|
||||
* @input_bus_flags:
|
||||
*
|
||||
* Tells whether the bridge samples the digital input signal
|
||||
* from the display engine on the positive or negative edge of the
|
||||
* clock, this should reuse the DRM_BUS_FLAG_PIXDATA_[POS|NEG]EDGE
|
||||
* bitwise flags from the DRM connector (bit 2 and 3 valid).
|
||||
* Tells what additional settings for the pixel data on the bus
|
||||
* this bridge requires (like pixel signal polarity). See also
|
||||
* &drm_display_info->bus_flags.
|
||||
*/
|
||||
u32 sampling_edge;
|
||||
u32 input_bus_flags;
|
||||
/**
|
||||
* @setup_time_ps:
|
||||
*
|
||||
|
|
|
@ -253,6 +253,68 @@ enum drm_panel_orientation {
|
|||
DRM_MODE_PANEL_ORIENTATION_RIGHT_UP,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum drm_bus_flags - bus_flags info for &drm_display_info
|
||||
*
|
||||
* This enum defines signal polarities and clock edge information for signals on
|
||||
* a bus as bitmask flags.
|
||||
*
|
||||
* The clock edge information is conveyed by two sets of symbols,
|
||||
* DRM_BUS_FLAGS_*_DRIVE_\* and DRM_BUS_FLAGS_*_SAMPLE_\*. When this enum is
|
||||
* used to describe a bus from the point of view of the transmitter, the
|
||||
* \*_DRIVE_\* flags should be used. When used from the point of view of the
|
||||
* receiver, the \*_SAMPLE_\* flags should be used. The \*_DRIVE_\* and
|
||||
* \*_SAMPLE_\* flags alias each other, with the \*_SAMPLE_POSEDGE and
|
||||
* \*_SAMPLE_NEGEDGE flags being equal to \*_DRIVE_NEGEDGE and \*_DRIVE_POSEDGE
|
||||
* respectively. This simplifies code as signals are usually sampled on the
|
||||
* opposite edge of the driving edge. Transmitters and receivers may however
|
||||
* need to take other signal timings into account to convert between driving
|
||||
* and sample edges.
|
||||
*
|
||||
* @DRM_BUS_FLAG_DE_LOW: The Data Enable signal is active low
|
||||
* @DRM_BUS_FLAG_DE_HIGH: The Data Enable signal is active high
|
||||
* @DRM_BUS_FLAG_PIXDATA_POSEDGE: Legacy value, do not use
|
||||
* @DRM_BUS_FLAG_PIXDATA_NEGEDGE: Legacy value, do not use
|
||||
* @DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE: Data is driven on the rising edge of
|
||||
* the pixel clock
|
||||
* @DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE: Data is driven on the falling edge of
|
||||
* the pixel clock
|
||||
* @DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE: Data is sampled on the rising edge of
|
||||
* the pixel clock
|
||||
* @DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE: Data is sampled on the falling edge of
|
||||
* the pixel clock
|
||||
* @DRM_BUS_FLAG_DATA_MSB_TO_LSB: Data is transmitted MSB to LSB on the bus
|
||||
* @DRM_BUS_FLAG_DATA_LSB_TO_MSB: Data is transmitted LSB to MSB on the bus
|
||||
* @DRM_BUS_FLAG_SYNC_POSEDGE: Legacy value, do not use
|
||||
* @DRM_BUS_FLAG_SYNC_NEGEDGE: Legacy value, do not use
|
||||
* @DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE: Sync signals are driven on the rising
|
||||
* edge of the pixel clock
|
||||
* @DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE: Sync signals are driven on the falling
|
||||
* edge of the pixel clock
|
||||
* @DRM_BUS_FLAG_SYNC_SAMPLE_POSEDGE: Sync signals are sampled on the rising
|
||||
* edge of the pixel clock
|
||||
* @DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE: Sync signals are sampled on the falling
|
||||
* edge of the pixel clock
|
||||
*/
|
||||
enum drm_bus_flags {
|
||||
DRM_BUS_FLAG_DE_LOW = BIT(0),
|
||||
DRM_BUS_FLAG_DE_HIGH = BIT(1),
|
||||
DRM_BUS_FLAG_PIXDATA_POSEDGE = BIT(2),
|
||||
DRM_BUS_FLAG_PIXDATA_NEGEDGE = BIT(3),
|
||||
DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE = DRM_BUS_FLAG_PIXDATA_POSEDGE,
|
||||
DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE = DRM_BUS_FLAG_PIXDATA_NEGEDGE,
|
||||
DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE = DRM_BUS_FLAG_PIXDATA_NEGEDGE,
|
||||
DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE = DRM_BUS_FLAG_PIXDATA_POSEDGE,
|
||||
DRM_BUS_FLAG_DATA_MSB_TO_LSB = BIT(4),
|
||||
DRM_BUS_FLAG_DATA_LSB_TO_MSB = BIT(5),
|
||||
DRM_BUS_FLAG_SYNC_POSEDGE = BIT(6),
|
||||
DRM_BUS_FLAG_SYNC_NEGEDGE = BIT(7),
|
||||
DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE = DRM_BUS_FLAG_SYNC_POSEDGE,
|
||||
DRM_BUS_FLAG_SYNC_DRIVE_NEGEDGE = DRM_BUS_FLAG_SYNC_NEGEDGE,
|
||||
DRM_BUS_FLAG_SYNC_SAMPLE_POSEDGE = DRM_BUS_FLAG_SYNC_NEGEDGE,
|
||||
DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE = DRM_BUS_FLAG_SYNC_POSEDGE,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct drm_display_info - runtime data about the connected sink
|
||||
*
|
||||
|
@ -328,24 +390,10 @@ struct drm_display_info {
|
|||
*/
|
||||
unsigned int num_bus_formats;
|
||||
|
||||
#define DRM_BUS_FLAG_DE_LOW (1<<0)
|
||||
#define DRM_BUS_FLAG_DE_HIGH (1<<1)
|
||||
/* drive data on pos. edge */
|
||||
#define DRM_BUS_FLAG_PIXDATA_POSEDGE (1<<2)
|
||||
/* drive data on neg. edge */
|
||||
#define DRM_BUS_FLAG_PIXDATA_NEGEDGE (1<<3)
|
||||
/* data is transmitted MSB to LSB on the bus */
|
||||
#define DRM_BUS_FLAG_DATA_MSB_TO_LSB (1<<4)
|
||||
/* data is transmitted LSB to MSB on the bus */
|
||||
#define DRM_BUS_FLAG_DATA_LSB_TO_MSB (1<<5)
|
||||
/* drive sync on pos. edge */
|
||||
#define DRM_BUS_FLAG_SYNC_POSEDGE (1<<6)
|
||||
/* drive sync on neg. edge */
|
||||
#define DRM_BUS_FLAG_SYNC_NEGEDGE (1<<7)
|
||||
|
||||
/**
|
||||
* @bus_flags: Additional information (like pixel signal polarity) for
|
||||
* the pixel data on the bus, using DRM_BUS_FLAGS\_ defines.
|
||||
* the pixel data on the bus, using &enum drm_bus_flags values
|
||||
* DRM_BUS_FLAGS\_.
|
||||
*/
|
||||
u32 bus_flags;
|
||||
|
||||
|
|
Loading…
Reference in New Issue