drm/panel: Changes for v3.20-rc1
This contains the long-awaited drm_bridge series that makes Chromebooks work for people. I had thought this would've been perfect by now, but then I go and build test it and the first thing it does is yell about a recursive dependency. I fixed that up because I was feeling bad for not getting around to look at this earlier. Biseds that there is new support for two more panels, a couple of fixup patches to the Sharp LQ101R1SX01 dual-channel DSI panel driver and a potential NULL pointer dereference fix. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAABAgAGBQJUyKWaAAoJEN0jrNd/PrOhtEkP/jI1A4UKGTWsMPrWa2Sco6Vm afFYHX/7UEARLpXeI86dV/cIY3ec9uLPTJrXhZT8qvi14XXnQjyc3ku1TXlCwvBS OinFu6J1ABPnmtLvItJY4lc9/AkVQ8NVKDgdCEwo6bVJX2BEdMVcvT2byzkpdmMQ hcJe0aK0UFPiuw35TFl4yfVeTsliPVrHI4eSMzODQNPGpZVZ5098E77B3PjHnVOD pW/YIl/4llR3hsHn6lso7eoBOVpUM6dm3cd08UFKEkhq+ICwe2Q9OBOcAQdQVnRb V7by53YYnD+5nASE+vz1ZPpiR9CJNwwCOtRt1QpO9pHlxjkr2fJfgdu5Tgg6MbnS GI/sXpyKvMATpSPzB5/a1dCbHEcvs9W1Wf9jjyL2OmG5zKboGCIp2BOvOGkmo6re jpVPfzClfXJXuT5mVDi9xphFT3fR4HIfAqbm+km3RvH9MMCL0ZqhTqcyANVXskjb +brKUI9704MyPFx1AAfYjRHD0NLzKNTKQECDGuD+gUkuViyM+E5tNGgm6Szr53J3 IuRI3zUKCnMoNbLi3buslebu3/Bmd01SvkTpm8VOTw1ey8bEFEhGephTO5koaFuT 4GhH5sBNIx+mopOGazLpM9A0h7Utxq1PXoaQY9SRbiQNmyGlQuSEyf4VmrwQySgL TZr2yx/3tIVUagkwzf8K =5PkY -----END PGP SIGNATURE----- Merge tag 'drm/panel/for-3.20-rc1' of git://anongit.freedesktop.org/tegra/linux into drm-next drm/panel: Changes for v3.20-rc1 This contains the long-awaited drm_bridge series that makes Chromebooks work for people. I had thought this would've been perfect by now, but then I go and build test it and the first thing it does is yell about a recursive dependency. I fixed that up because I was feeling bad for not getting around to look at this earlier. Biseds that there is new support for two more panels, a couple of fixup patches to the Sharp LQ101R1SX01 dual-channel DSI panel driver and a potential NULL pointer dereference fix. * tag 'drm/panel/for-3.20-rc1' of git://anongit.freedesktop.org/tegra/linux: (23 commits) drm/bridge: dw-hdmi: Adapt to bridge API change drm/sti: fixup for bridge interface drm/bridge: dw-hdmi: Fix return error path drm: Check the right variable when setting formats Documentation: bridge: Add documentation for ps8622 DT properties Documentation: devicetree: Add vendor prefix for parade Documentation: drm: bridge: move to video/bridge drm/bridge: ptn3460: use gpiod interface drm/bridge: ptn3460: probe connector at the end of bridge attach drm/bridge: ptn3460: support drm_panel drm/exynos: dp: support drm_bridge drm/bridge: ptn3460: Convert to I2C driver model drm/bridge: make bridge registration independent of drm flow drm/bridge: do not pass drm_bridge_funcs to drm_bridge_init drm/bridge: ptn3460: Few trivial cleanups drm/panel: simple: Add AVIC TM070DDH03 panel support of: Add vendor prefix for Shanghai AVIC Optoelectronics Co., Ltd. drm/panel: sharp: lq101r1sx01: Remove unneeded include drm/panel: sharp: lq101r1sx01: Respect power timings drm/panel: sharp: lq101r1sx01: Add delay after display on ...
This commit is contained in:
commit
7b83741bf7
|
@ -0,0 +1,7 @@
|
|||
Shanghai AVIC Optoelectronics 7" 1024x600 color TFT-LCD panel
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "avic,tm070ddh03"
|
||||
|
||||
This binding is compatible with the simple-panel binding, which is specified
|
||||
in simple-panel.txt in this directory.
|
|
@ -0,0 +1,7 @@
|
|||
GiantPlus GPG48273QS5 4.3" (480x272) WQVGA TFT LCD panel
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "giantplus,gpg48273qs5"
|
||||
|
||||
This binding is compatible with the simple-panel binding, which is specified
|
||||
in simple-panel.txt in this directory.
|
|
@ -23,6 +23,7 @@ armadeus ARMadeus Systems SARL
|
|||
atmel Atmel Corporation
|
||||
auo AU Optronics Corporation
|
||||
avago Avago Technologies
|
||||
avic Shanghai AVIC Optoelectronics Co., Ltd.
|
||||
bosch Bosch Sensortec GmbH
|
||||
brcm Broadcom Corporation
|
||||
buffalo Buffalo, Inc.
|
||||
|
@ -62,6 +63,7 @@ fsl Freescale Semiconductor
|
|||
GEFanuc GE Fanuc Intelligent Platforms Embedded Systems, Inc.
|
||||
gef GE Fanuc Intelligent Platforms Embedded Systems, Inc.
|
||||
geniatech Geniatech, Inc.
|
||||
giantplus Giantplus Technology Co., Ltd.
|
||||
globalscale Globalscale Technologies, Inc.
|
||||
gmt Global Mixed-mode Technology, Inc.
|
||||
google Google, Inc.
|
||||
|
@ -119,6 +121,7 @@ nxp NXP Semiconductors
|
|||
onnn ON Semiconductor Corp.
|
||||
opencores OpenCores.org
|
||||
panasonic Panasonic Corporation
|
||||
parade Parade Technologies Inc.
|
||||
pericom Pericom Technology Inc.
|
||||
phytec PHYTEC Messtechnik GmbH
|
||||
picochip Picochip Ltd
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
ps8622-bridge bindings
|
||||
|
||||
Required properties:
|
||||
- compatible: "parade,ps8622" or "parade,ps8625"
|
||||
- reg: first i2c address of the bridge
|
||||
- sleep-gpios: OF device-tree gpio specification for PD_ pin.
|
||||
- reset-gpios: OF device-tree gpio specification for RST_ pin.
|
||||
|
||||
Optional properties:
|
||||
- lane-count: number of DP lanes to use
|
||||
- use-external-pwm: backlight will be controlled by an external PWM
|
||||
- video interfaces: Device node can contain video interface port
|
||||
nodes for panel according to [1].
|
||||
|
||||
[1]: Documentation/devicetree/bindings/media/video-interfaces.txt
|
||||
|
||||
Example:
|
||||
lvds-bridge@48 {
|
||||
compatible = "parade,ps8622";
|
||||
reg = <0x48>;
|
||||
sleep-gpios = <&gpc3 6 1 0 0>;
|
||||
reset-gpios = <&gpc3 1 1 0 0>;
|
||||
lane-count = <1>;
|
||||
ports {
|
||||
port@0 {
|
||||
bridge_out: endpoint {
|
||||
remote-endpoint = <&panel_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
|
@ -3,8 +3,8 @@ ptn3460 bridge bindings
|
|||
Required properties:
|
||||
- compatible: "nxp,ptn3460"
|
||||
- reg: i2c address of the bridge
|
||||
- powerdown-gpio: OF device-tree gpio specification
|
||||
- reset-gpio: OF device-tree gpio specification
|
||||
- powerdown-gpio: OF device-tree gpio specification for PD_N pin.
|
||||
- reset-gpio: OF device-tree gpio specification for RST_N pin.
|
||||
- edid-emulation: The EDID emulation entry to use
|
||||
+-------+------------+------------------+
|
||||
| Value | Resolution | Description |
|
||||
|
@ -17,6 +17,11 @@ Required properties:
|
|||
| 6 | 1600x900 | ChiMei M215HGE |
|
||||
+-------+------------+------------------+
|
||||
|
||||
- video interfaces: Device node can contain video interface port
|
||||
nodes for panel according to [1].
|
||||
|
||||
[1]: Documentation/devicetree/bindings/media/video-interfaces.txt
|
||||
|
||||
Example:
|
||||
lvds-bridge@20 {
|
||||
compatible = "nxp,ptn3460";
|
||||
|
@ -24,4 +29,11 @@ Example:
|
|||
powerdown-gpio = <&gpy2 5 1 0 0>;
|
||||
reset-gpio = <&gpx1 5 1 0 0>;
|
||||
edid-emulation = <5>;
|
||||
ports {
|
||||
port@0 {
|
||||
bridge_out: endpoint {
|
||||
remote-endpoint = <&panel_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
|
@ -66,6 +66,10 @@ Optional properties for dp-controller:
|
|||
Hotplug detect GPIO.
|
||||
Indicates which GPIO should be used for hotplug
|
||||
detection
|
||||
-video interfaces: Device node can contain video interface port
|
||||
nodes according to [1].
|
||||
|
||||
[1]: Documentation/devicetree/bindings/media/video-interfaces.txt
|
||||
|
||||
Example:
|
||||
|
||||
|
@ -105,4 +109,12 @@ Board Specific portion:
|
|||
vsync-len = <6>;
|
||||
};
|
||||
};
|
||||
|
||||
ports {
|
||||
port@0 {
|
||||
dp_out: endpoint {
|
||||
remote-endpoint = <&bridge_in>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -14,7 +14,7 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \
|
|||
drm_info.o drm_debugfs.o drm_encoder_slave.o \
|
||||
drm_trace_points.o drm_global.o drm_prime.o \
|
||||
drm_rect.o drm_vma_manager.o drm_flip_work.o \
|
||||
drm_modeset_lock.o drm_atomic.o
|
||||
drm_modeset_lock.o drm_atomic.o drm_bridge.o
|
||||
|
||||
drm-$(CONFIG_COMPAT) += drm_ioc32.o
|
||||
drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
config DRM_PTN3460
|
||||
tristate "PTN3460 DP/LVDS bridge"
|
||||
depends on DRM
|
||||
select DRM_KMS_HELPER
|
||||
---help---
|
||||
|
||||
config DRM_DW_HDMI
|
||||
tristate
|
||||
depends on DRM
|
||||
select DRM_KMS_HELPER
|
||||
|
||||
config DRM_PTN3460
|
||||
tristate "PTN3460 DP/LVDS bridge"
|
||||
depends on DRM
|
||||
depends on OF
|
||||
select DRM_KMS_HELPER
|
||||
select DRM_PANEL
|
||||
---help---
|
||||
ptn3460 eDP-LVDS bridge chip driver.
|
||||
|
|
|
@ -1373,12 +1373,6 @@ static void dw_hdmi_bridge_enable(struct drm_bridge *bridge)
|
|||
dw_hdmi_poweron(hdmi);
|
||||
}
|
||||
|
||||
static void dw_hdmi_bridge_destroy(struct drm_bridge *bridge)
|
||||
{
|
||||
drm_bridge_cleanup(bridge);
|
||||
kfree(bridge);
|
||||
}
|
||||
|
||||
static void dw_hdmi_bridge_nop(struct drm_bridge *bridge)
|
||||
{
|
||||
/* do nothing */
|
||||
|
@ -1468,7 +1462,6 @@ struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
|
|||
.post_disable = dw_hdmi_bridge_nop,
|
||||
.mode_set = dw_hdmi_bridge_mode_set,
|
||||
.mode_fixup = dw_hdmi_bridge_mode_fixup,
|
||||
.destroy = dw_hdmi_bridge_destroy,
|
||||
};
|
||||
|
||||
static irqreturn_t dw_hdmi_hardirq(int irq, void *dev_id)
|
||||
|
@ -1531,8 +1524,8 @@ static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
|
|||
|
||||
hdmi->bridge = bridge;
|
||||
bridge->driver_private = hdmi;
|
||||
|
||||
ret = drm_bridge_init(drm, bridge, &dw_hdmi_bridge_funcs);
|
||||
bridge->funcs = &dw_hdmi_bridge_funcs;
|
||||
ret = drm_bridge_attach(drm, bridge);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to initialize bridge with drm\n");
|
||||
return -EINVAL;
|
||||
|
@ -1649,7 +1642,7 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
|
|||
dw_hdmi_irq, IRQF_SHARED,
|
||||
dev_name(dev), hdmi);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto err_iahb;
|
||||
|
||||
/*
|
||||
* To prevent overflows in HDMI_IH_FC_STAT2, set the clk regenerator
|
||||
|
|
|
@ -13,20 +13,23 @@
|
|||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/of_graph.h>
|
||||
|
||||
#include "drmP.h"
|
||||
#include "drm_edid.h"
|
||||
#include "drm_crtc.h"
|
||||
#include "drm_crtc_helper.h"
|
||||
#include <drm/drm_panel.h>
|
||||
|
||||
#include "bridge/ptn3460.h"
|
||||
|
||||
#include "drm_crtc.h"
|
||||
#include "drm_crtc_helper.h"
|
||||
#include "drm_edid.h"
|
||||
#include "drmP.h"
|
||||
|
||||
#define PTN3460_EDID_ADDR 0x0
|
||||
#define PTN3460_EDID_EMULATION_ADDR 0x84
|
||||
#define PTN3460_EDID_ENABLE_EMULATION 0
|
||||
|
@ -36,15 +39,27 @@
|
|||
struct ptn3460_bridge {
|
||||
struct drm_connector connector;
|
||||
struct i2c_client *client;
|
||||
struct drm_encoder *encoder;
|
||||
struct drm_bridge *bridge;
|
||||
struct drm_bridge bridge;
|
||||
struct edid *edid;
|
||||
int gpio_pd_n;
|
||||
int gpio_rst_n;
|
||||
struct drm_panel *panel;
|
||||
struct gpio_desc *gpio_pd_n;
|
||||
struct gpio_desc *gpio_rst_n;
|
||||
u32 edid_emulation;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
static inline struct ptn3460_bridge *
|
||||
bridge_to_ptn3460(struct drm_bridge *bridge)
|
||||
{
|
||||
return container_of(bridge, struct ptn3460_bridge, bridge);
|
||||
}
|
||||
|
||||
static inline struct ptn3460_bridge *
|
||||
connector_to_ptn3460(struct drm_connector *connector)
|
||||
{
|
||||
return container_of(connector, struct ptn3460_bridge, connector);
|
||||
}
|
||||
|
||||
static int ptn3460_read_bytes(struct ptn3460_bridge *ptn_bridge, char addr,
|
||||
u8 *buf, int len)
|
||||
{
|
||||
|
@ -92,7 +107,7 @@ static int ptn3460_select_edid(struct ptn3460_bridge *ptn_bridge)
|
|||
ret = ptn3460_write_byte(ptn_bridge, PTN3460_EDID_SRAM_LOAD_ADDR,
|
||||
ptn_bridge->edid_emulation);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to transfer edid to sram, ret=%d\n", ret);
|
||||
DRM_ERROR("Failed to transfer EDID to sram, ret=%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -102,7 +117,7 @@ static int ptn3460_select_edid(struct ptn3460_bridge *ptn_bridge)
|
|||
|
||||
ret = ptn3460_write_byte(ptn_bridge, PTN3460_EDID_EMULATION_ADDR, val);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to write edid value, ret=%d\n", ret);
|
||||
DRM_ERROR("Failed to write EDID value, ret=%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -111,19 +126,21 @@ static int ptn3460_select_edid(struct ptn3460_bridge *ptn_bridge)
|
|||
|
||||
static void ptn3460_pre_enable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct ptn3460_bridge *ptn_bridge = bridge->driver_private;
|
||||
struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
|
||||
int ret;
|
||||
|
||||
if (ptn_bridge->enabled)
|
||||
return;
|
||||
|
||||
if (gpio_is_valid(ptn_bridge->gpio_pd_n))
|
||||
gpio_set_value(ptn_bridge->gpio_pd_n, 1);
|
||||
gpiod_set_value(ptn_bridge->gpio_pd_n, 1);
|
||||
|
||||
if (gpio_is_valid(ptn_bridge->gpio_rst_n)) {
|
||||
gpio_set_value(ptn_bridge->gpio_rst_n, 0);
|
||||
udelay(10);
|
||||
gpio_set_value(ptn_bridge->gpio_rst_n, 1);
|
||||
gpiod_set_value(ptn_bridge->gpio_rst_n, 0);
|
||||
usleep_range(10, 20);
|
||||
gpiod_set_value(ptn_bridge->gpio_rst_n, 1);
|
||||
|
||||
if (drm_panel_prepare(ptn_bridge->panel)) {
|
||||
DRM_ERROR("failed to prepare panel\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -135,73 +152,67 @@ static void ptn3460_pre_enable(struct drm_bridge *bridge)
|
|||
|
||||
ret = ptn3460_select_edid(ptn_bridge);
|
||||
if (ret)
|
||||
DRM_ERROR("Select edid failed ret=%d\n", ret);
|
||||
DRM_ERROR("Select EDID failed ret=%d\n", ret);
|
||||
|
||||
ptn_bridge->enabled = true;
|
||||
}
|
||||
|
||||
static void ptn3460_enable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
|
||||
|
||||
if (drm_panel_enable(ptn_bridge->panel)) {
|
||||
DRM_ERROR("failed to enable panel\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void ptn3460_disable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct ptn3460_bridge *ptn_bridge = bridge->driver_private;
|
||||
struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
|
||||
|
||||
if (!ptn_bridge->enabled)
|
||||
return;
|
||||
|
||||
ptn_bridge->enabled = false;
|
||||
|
||||
if (gpio_is_valid(ptn_bridge->gpio_rst_n))
|
||||
gpio_set_value(ptn_bridge->gpio_rst_n, 1);
|
||||
if (drm_panel_disable(ptn_bridge->panel)) {
|
||||
DRM_ERROR("failed to disable panel\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (gpio_is_valid(ptn_bridge->gpio_pd_n))
|
||||
gpio_set_value(ptn_bridge->gpio_pd_n, 0);
|
||||
gpiod_set_value(ptn_bridge->gpio_rst_n, 1);
|
||||
gpiod_set_value(ptn_bridge->gpio_pd_n, 0);
|
||||
}
|
||||
|
||||
static void ptn3460_post_disable(struct drm_bridge *bridge)
|
||||
{
|
||||
struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
|
||||
|
||||
if (drm_panel_unprepare(ptn_bridge->panel)) {
|
||||
DRM_ERROR("failed to unprepare panel\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void ptn3460_bridge_destroy(struct drm_bridge *bridge)
|
||||
{
|
||||
struct ptn3460_bridge *ptn_bridge = bridge->driver_private;
|
||||
|
||||
drm_bridge_cleanup(bridge);
|
||||
if (gpio_is_valid(ptn_bridge->gpio_pd_n))
|
||||
gpio_free(ptn_bridge->gpio_pd_n);
|
||||
if (gpio_is_valid(ptn_bridge->gpio_rst_n))
|
||||
gpio_free(ptn_bridge->gpio_rst_n);
|
||||
/* Nothing else to free, we've got devm allocated memory */
|
||||
}
|
||||
|
||||
struct drm_bridge_funcs ptn3460_bridge_funcs = {
|
||||
.pre_enable = ptn3460_pre_enable,
|
||||
.enable = ptn3460_enable,
|
||||
.disable = ptn3460_disable,
|
||||
.post_disable = ptn3460_post_disable,
|
||||
.destroy = ptn3460_bridge_destroy,
|
||||
};
|
||||
|
||||
int ptn3460_get_modes(struct drm_connector *connector)
|
||||
static int ptn3460_get_modes(struct drm_connector *connector)
|
||||
{
|
||||
struct ptn3460_bridge *ptn_bridge;
|
||||
u8 *edid;
|
||||
int ret, num_modes;
|
||||
int ret, num_modes = 0;
|
||||
bool power_off;
|
||||
|
||||
ptn_bridge = container_of(connector, struct ptn3460_bridge, connector);
|
||||
ptn_bridge = connector_to_ptn3460(connector);
|
||||
|
||||
if (ptn_bridge->edid)
|
||||
return drm_add_edid_modes(connector, ptn_bridge->edid);
|
||||
|
||||
power_off = !ptn_bridge->enabled;
|
||||
ptn3460_pre_enable(ptn_bridge->bridge);
|
||||
ptn3460_pre_enable(&ptn_bridge->bridge);
|
||||
|
||||
edid = kmalloc(EDID_LENGTH, GFP_KERNEL);
|
||||
if (!edid) {
|
||||
DRM_ERROR("Failed to allocate edid\n");
|
||||
DRM_ERROR("Failed to allocate EDID\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -209,7 +220,6 @@ int ptn3460_get_modes(struct drm_connector *connector)
|
|||
EDID_LENGTH);
|
||||
if (ret) {
|
||||
kfree(edid);
|
||||
num_modes = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -220,124 +230,188 @@ int ptn3460_get_modes(struct drm_connector *connector)
|
|||
|
||||
out:
|
||||
if (power_off)
|
||||
ptn3460_disable(ptn_bridge->bridge);
|
||||
ptn3460_disable(&ptn_bridge->bridge);
|
||||
|
||||
return num_modes;
|
||||
}
|
||||
|
||||
struct drm_encoder *ptn3460_best_encoder(struct drm_connector *connector)
|
||||
static struct drm_encoder *ptn3460_best_encoder(struct drm_connector *connector)
|
||||
{
|
||||
struct ptn3460_bridge *ptn_bridge;
|
||||
struct ptn3460_bridge *ptn_bridge = connector_to_ptn3460(connector);
|
||||
|
||||
ptn_bridge = container_of(connector, struct ptn3460_bridge, connector);
|
||||
|
||||
return ptn_bridge->encoder;
|
||||
return ptn_bridge->bridge.encoder;
|
||||
}
|
||||
|
||||
struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = {
|
||||
static struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = {
|
||||
.get_modes = ptn3460_get_modes,
|
||||
.best_encoder = ptn3460_best_encoder,
|
||||
};
|
||||
|
||||
enum drm_connector_status ptn3460_detect(struct drm_connector *connector,
|
||||
static enum drm_connector_status ptn3460_detect(struct drm_connector *connector,
|
||||
bool force)
|
||||
{
|
||||
return connector_status_connected;
|
||||
}
|
||||
|
||||
void ptn3460_connector_destroy(struct drm_connector *connector)
|
||||
static void ptn3460_connector_destroy(struct drm_connector *connector)
|
||||
{
|
||||
drm_connector_cleanup(connector);
|
||||
}
|
||||
|
||||
struct drm_connector_funcs ptn3460_connector_funcs = {
|
||||
static struct drm_connector_funcs ptn3460_connector_funcs = {
|
||||
.dpms = drm_helper_connector_dpms,
|
||||
.fill_modes = drm_helper_probe_single_connector_modes,
|
||||
.detect = ptn3460_detect,
|
||||
.destroy = ptn3460_connector_destroy,
|
||||
};
|
||||
|
||||
int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder,
|
||||
struct i2c_client *client, struct device_node *node)
|
||||
int ptn3460_bridge_attach(struct drm_bridge *bridge)
|
||||
{
|
||||
struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
|
||||
int ret;
|
||||
struct drm_bridge *bridge;
|
||||
struct ptn3460_bridge *ptn_bridge;
|
||||
|
||||
bridge = devm_kzalloc(dev->dev, sizeof(*bridge), GFP_KERNEL);
|
||||
if (!bridge) {
|
||||
DRM_ERROR("Failed to allocate drm bridge\n");
|
||||
return -ENOMEM;
|
||||
if (!bridge->encoder) {
|
||||
DRM_ERROR("Parent encoder object not found");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ptn_bridge = devm_kzalloc(dev->dev, sizeof(*ptn_bridge), GFP_KERNEL);
|
||||
if (!ptn_bridge) {
|
||||
DRM_ERROR("Failed to allocate ptn bridge\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ptn_bridge->client = client;
|
||||
ptn_bridge->encoder = encoder;
|
||||
ptn_bridge->bridge = bridge;
|
||||
ptn_bridge->gpio_pd_n = of_get_named_gpio(node, "powerdown-gpio", 0);
|
||||
if (gpio_is_valid(ptn_bridge->gpio_pd_n)) {
|
||||
ret = gpio_request_one(ptn_bridge->gpio_pd_n,
|
||||
GPIOF_OUT_INIT_HIGH, "PTN3460_PD_N");
|
||||
if (ret) {
|
||||
DRM_ERROR("Request powerdown-gpio failed (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ptn_bridge->gpio_rst_n = of_get_named_gpio(node, "reset-gpio", 0);
|
||||
if (gpio_is_valid(ptn_bridge->gpio_rst_n)) {
|
||||
/*
|
||||
* Request the reset pin low to avoid the bridge being
|
||||
* initialized prematurely
|
||||
*/
|
||||
ret = gpio_request_one(ptn_bridge->gpio_rst_n,
|
||||
GPIOF_OUT_INIT_LOW, "PTN3460_RST_N");
|
||||
if (ret) {
|
||||
DRM_ERROR("Request reset-gpio failed (%d)\n", ret);
|
||||
gpio_free(ptn_bridge->gpio_pd_n);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(node, "edid-emulation",
|
||||
&ptn_bridge->edid_emulation);
|
||||
if (ret) {
|
||||
DRM_ERROR("Can't read edid emulation value\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = drm_bridge_init(dev, bridge, &ptn3460_bridge_funcs);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to initialize bridge with drm\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
bridge->driver_private = ptn_bridge;
|
||||
encoder->bridge = bridge;
|
||||
|
||||
ret = drm_connector_init(dev, &ptn_bridge->connector,
|
||||
ptn_bridge->connector.polled = DRM_CONNECTOR_POLL_HPD;
|
||||
ret = drm_connector_init(bridge->dev, &ptn_bridge->connector,
|
||||
&ptn3460_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to initialize connector with drm\n");
|
||||
goto err;
|
||||
return ret;
|
||||
}
|
||||
drm_connector_helper_add(&ptn_bridge->connector,
|
||||
&ptn3460_connector_helper_funcs);
|
||||
&ptn3460_connector_helper_funcs);
|
||||
drm_connector_register(&ptn_bridge->connector);
|
||||
drm_mode_connector_attach_encoder(&ptn_bridge->connector, encoder);
|
||||
drm_mode_connector_attach_encoder(&ptn_bridge->connector,
|
||||
bridge->encoder);
|
||||
|
||||
return 0;
|
||||
if (ptn_bridge->panel)
|
||||
drm_panel_attach(ptn_bridge->panel, &ptn_bridge->connector);
|
||||
|
||||
drm_helper_hpd_irq_event(ptn_bridge->connector.dev);
|
||||
|
||||
err:
|
||||
if (gpio_is_valid(ptn_bridge->gpio_pd_n))
|
||||
gpio_free(ptn_bridge->gpio_pd_n);
|
||||
if (gpio_is_valid(ptn_bridge->gpio_rst_n))
|
||||
gpio_free(ptn_bridge->gpio_rst_n);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(ptn3460_init);
|
||||
|
||||
static struct drm_bridge_funcs ptn3460_bridge_funcs = {
|
||||
.pre_enable = ptn3460_pre_enable,
|
||||
.enable = ptn3460_enable,
|
||||
.disable = ptn3460_disable,
|
||||
.post_disable = ptn3460_post_disable,
|
||||
.attach = ptn3460_bridge_attach,
|
||||
};
|
||||
|
||||
static int ptn3460_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct ptn3460_bridge *ptn_bridge;
|
||||
struct device_node *endpoint, *panel_node;
|
||||
int ret;
|
||||
|
||||
ptn_bridge = devm_kzalloc(dev, sizeof(*ptn_bridge), GFP_KERNEL);
|
||||
if (!ptn_bridge) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
|
||||
if (endpoint) {
|
||||
panel_node = of_graph_get_remote_port_parent(endpoint);
|
||||
if (panel_node) {
|
||||
ptn_bridge->panel = of_drm_find_panel(panel_node);
|
||||
of_node_put(panel_node);
|
||||
if (!ptn_bridge->panel)
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
}
|
||||
|
||||
ptn_bridge->client = client;
|
||||
|
||||
ptn_bridge->gpio_pd_n = devm_gpiod_get(&client->dev, "powerdown");
|
||||
if (IS_ERR(ptn_bridge->gpio_pd_n)) {
|
||||
ret = PTR_ERR(ptn_bridge->gpio_pd_n);
|
||||
dev_err(dev, "cannot get gpio_pd_n %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = gpiod_direction_output(ptn_bridge->gpio_pd_n, 1);
|
||||
if (ret) {
|
||||
DRM_ERROR("cannot configure gpio_pd_n\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ptn_bridge->gpio_rst_n = devm_gpiod_get(&client->dev, "reset");
|
||||
if (IS_ERR(ptn_bridge->gpio_rst_n)) {
|
||||
ret = PTR_ERR(ptn_bridge->gpio_rst_n);
|
||||
DRM_ERROR("cannot get gpio_rst_n %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
/*
|
||||
* Request the reset pin low to avoid the bridge being
|
||||
* initialized prematurely
|
||||
*/
|
||||
ret = gpiod_direction_output(ptn_bridge->gpio_rst_n, 0);
|
||||
if (ret) {
|
||||
DRM_ERROR("cannot configure gpio_rst_n\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(dev->of_node, "edid-emulation",
|
||||
&ptn_bridge->edid_emulation);
|
||||
if (ret) {
|
||||
dev_err(dev, "Can't read EDID emulation value\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ptn_bridge->bridge.funcs = &ptn3460_bridge_funcs;
|
||||
ptn_bridge->bridge.of_node = dev->of_node;
|
||||
ret = drm_bridge_add(&ptn_bridge->bridge);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to add bridge\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(client, ptn_bridge);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ptn3460_remove(struct i2c_client *client)
|
||||
{
|
||||
struct ptn3460_bridge *ptn_bridge = i2c_get_clientdata(client);
|
||||
|
||||
drm_bridge_remove(&ptn_bridge->bridge);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ptn3460_i2c_table[] = {
|
||||
{"nxp,ptn3460", 0},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ptn3460_i2c_table);
|
||||
|
||||
static const struct of_device_id ptn3460_match[] = {
|
||||
{ .compatible = "nxp,ptn3460" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ptn3460_match);
|
||||
|
||||
static struct i2c_driver ptn3460_driver = {
|
||||
.id_table = ptn3460_i2c_table,
|
||||
.probe = ptn3460_probe,
|
||||
.remove = ptn3460_remove,
|
||||
.driver = {
|
||||
.name = "nxp,ptn3460",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = ptn3460_match,
|
||||
},
|
||||
};
|
||||
module_i2c_driver(ptn3460_driver);
|
||||
|
||||
MODULE_AUTHOR("Sean Paul <seanpaul@chromium.org>");
|
||||
MODULE_DESCRIPTION("NXP ptn3460 eDP-LVDS converter driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright (c) 2014 Samsung Electronics Co., Ltd
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sub license,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <drm/drm_crtc.h>
|
||||
|
||||
#include "drm/drmP.h"
|
||||
|
||||
static DEFINE_MUTEX(bridge_lock);
|
||||
static LIST_HEAD(bridge_list);
|
||||
|
||||
int drm_bridge_add(struct drm_bridge *bridge)
|
||||
{
|
||||
mutex_lock(&bridge_lock);
|
||||
list_add_tail(&bridge->list, &bridge_list);
|
||||
mutex_unlock(&bridge_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_bridge_add);
|
||||
|
||||
void drm_bridge_remove(struct drm_bridge *bridge)
|
||||
{
|
||||
mutex_lock(&bridge_lock);
|
||||
list_del_init(&bridge->list);
|
||||
mutex_unlock(&bridge_lock);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_bridge_remove);
|
||||
|
||||
extern int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge)
|
||||
{
|
||||
if (!dev || !bridge)
|
||||
return -EINVAL;
|
||||
|
||||
if (bridge->dev)
|
||||
return -EBUSY;
|
||||
|
||||
bridge->dev = dev;
|
||||
|
||||
if (bridge->funcs->attach)
|
||||
return bridge->funcs->attach(bridge);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_bridge_attach);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
struct drm_bridge *of_drm_find_bridge(struct device_node *np)
|
||||
{
|
||||
struct drm_bridge *bridge;
|
||||
|
||||
mutex_lock(&bridge_lock);
|
||||
|
||||
list_for_each_entry(bridge, &bridge_list, list) {
|
||||
if (bridge->of_node == np) {
|
||||
mutex_unlock(&bridge_lock);
|
||||
return bridge;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&bridge_lock);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(of_drm_find_bridge);
|
||||
#endif
|
||||
|
||||
MODULE_AUTHOR("Ajay Kumar <ajaykumar.rs@samsung.com>");
|
||||
MODULE_DESCRIPTION("DRM bridge infrastructure");
|
||||
MODULE_LICENSE("GPL and additional rights");
|
|
@ -787,7 +787,7 @@ int drm_display_info_set_bus_formats(struct drm_display_info *info,
|
|||
if (formats && num_formats) {
|
||||
fmts = kmemdup(formats, sizeof(*formats) * num_formats,
|
||||
GFP_KERNEL);
|
||||
if (!formats)
|
||||
if (!fmts)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
@ -1065,61 +1065,6 @@ void drm_connector_unplug_all(struct drm_device *dev)
|
|||
}
|
||||
EXPORT_SYMBOL(drm_connector_unplug_all);
|
||||
|
||||
/**
|
||||
* drm_bridge_init - initialize a drm transcoder/bridge
|
||||
* @dev: drm device
|
||||
* @bridge: transcoder/bridge to set up
|
||||
* @funcs: bridge function table
|
||||
*
|
||||
* Initialises a preallocated bridge. Bridges should be
|
||||
* subclassed as part of driver connector objects.
|
||||
*
|
||||
* Returns:
|
||||
* Zero on success, error code on failure.
|
||||
*/
|
||||
int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge,
|
||||
const struct drm_bridge_funcs *funcs)
|
||||
{
|
||||
int ret;
|
||||
|
||||
drm_modeset_lock_all(dev);
|
||||
|
||||
ret = drm_mode_object_get(dev, &bridge->base, DRM_MODE_OBJECT_BRIDGE);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
bridge->dev = dev;
|
||||
bridge->funcs = funcs;
|
||||
|
||||
list_add_tail(&bridge->head, &dev->mode_config.bridge_list);
|
||||
dev->mode_config.num_bridge++;
|
||||
|
||||
out:
|
||||
drm_modeset_unlock_all(dev);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_bridge_init);
|
||||
|
||||
/**
|
||||
* drm_bridge_cleanup - cleans up an initialised bridge
|
||||
* @bridge: bridge to cleanup
|
||||
*
|
||||
* Cleans up the bridge but doesn't free the object.
|
||||
*/
|
||||
void drm_bridge_cleanup(struct drm_bridge *bridge)
|
||||
{
|
||||
struct drm_device *dev = bridge->dev;
|
||||
|
||||
drm_modeset_lock_all(dev);
|
||||
drm_mode_object_put(dev, &bridge->base);
|
||||
list_del(&bridge->head);
|
||||
dev->mode_config.num_bridge--;
|
||||
drm_modeset_unlock_all(dev);
|
||||
|
||||
memset(bridge, 0, sizeof(*bridge));
|
||||
}
|
||||
EXPORT_SYMBOL(drm_bridge_cleanup);
|
||||
|
||||
/**
|
||||
* drm_encoder_init - Init a preallocated encoder
|
||||
* @dev: drm device
|
||||
|
@ -1715,7 +1660,6 @@ static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *gr
|
|||
total_objects += dev->mode_config.num_crtc;
|
||||
total_objects += dev->mode_config.num_connector;
|
||||
total_objects += dev->mode_config.num_encoder;
|
||||
total_objects += dev->mode_config.num_bridge;
|
||||
|
||||
group->id_list = kcalloc(total_objects, sizeof(uint32_t), GFP_KERNEL);
|
||||
if (!group->id_list)
|
||||
|
@ -1724,7 +1668,6 @@ static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *gr
|
|||
group->num_crtcs = 0;
|
||||
group->num_connectors = 0;
|
||||
group->num_encoders = 0;
|
||||
group->num_bridges = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1744,7 +1687,6 @@ int drm_mode_group_init_legacy_group(struct drm_device *dev,
|
|||
struct drm_crtc *crtc;
|
||||
struct drm_encoder *encoder;
|
||||
struct drm_connector *connector;
|
||||
struct drm_bridge *bridge;
|
||||
int ret;
|
||||
|
||||
ret = drm_mode_group_init(dev, group);
|
||||
|
@ -1762,11 +1704,6 @@ int drm_mode_group_init_legacy_group(struct drm_device *dev,
|
|||
group->id_list[group->num_crtcs + group->num_encoders +
|
||||
group->num_connectors++] = connector->base.id;
|
||||
|
||||
list_for_each_entry(bridge, &dev->mode_config.bridge_list, head)
|
||||
group->id_list[group->num_crtcs + group->num_encoders +
|
||||
group->num_connectors + group->num_bridges++] =
|
||||
bridge->base.id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(drm_mode_group_init_legacy_group);
|
||||
|
@ -5443,7 +5380,6 @@ void drm_mode_config_init(struct drm_device *dev)
|
|||
INIT_LIST_HEAD(&dev->mode_config.fb_list);
|
||||
INIT_LIST_HEAD(&dev->mode_config.crtc_list);
|
||||
INIT_LIST_HEAD(&dev->mode_config.connector_list);
|
||||
INIT_LIST_HEAD(&dev->mode_config.bridge_list);
|
||||
INIT_LIST_HEAD(&dev->mode_config.encoder_list);
|
||||
INIT_LIST_HEAD(&dev->mode_config.property_list);
|
||||
INIT_LIST_HEAD(&dev->mode_config.property_blob_list);
|
||||
|
@ -5483,7 +5419,6 @@ void drm_mode_config_cleanup(struct drm_device *dev)
|
|||
struct drm_connector *connector, *ot;
|
||||
struct drm_crtc *crtc, *ct;
|
||||
struct drm_encoder *encoder, *enct;
|
||||
struct drm_bridge *bridge, *brt;
|
||||
struct drm_framebuffer *fb, *fbt;
|
||||
struct drm_property *property, *pt;
|
||||
struct drm_property_blob *blob, *bt;
|
||||
|
@ -5494,11 +5429,6 @@ void drm_mode_config_cleanup(struct drm_device *dev)
|
|||
encoder->funcs->destroy(encoder);
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(bridge, brt,
|
||||
&dev->mode_config.bridge_list, head) {
|
||||
bridge->funcs->destroy(bridge);
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(connector, ot,
|
||||
&dev->mode_config.connector_list, head) {
|
||||
connector->funcs->destroy(connector);
|
||||
|
|
|
@ -323,8 +323,6 @@ EXPORT_SYMBOL(mipi_dsi_packet_format_is_long);
|
|||
int mipi_dsi_create_packet(struct mipi_dsi_packet *packet,
|
||||
const struct mipi_dsi_msg *msg)
|
||||
{
|
||||
const u8 *tx = msg->tx_buf;
|
||||
|
||||
if (!packet || !msg)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -353,8 +351,10 @@ int mipi_dsi_create_packet(struct mipi_dsi_packet *packet,
|
|||
packet->header[2] = (msg->tx_len >> 8) & 0xff;
|
||||
|
||||
packet->payload_length = msg->tx_len;
|
||||
packet->payload = tx;
|
||||
packet->payload = msg->tx_buf;
|
||||
} else {
|
||||
const u8 *tx = msg->tx_buf;
|
||||
|
||||
packet->header[1] = (msg->tx_len > 0) ? tx[0] : 0;
|
||||
packet->header[2] = (msg->tx_len > 1) ? tx[1] : 0;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/of_graph.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/component.h>
|
||||
#include <linux/phy/phy.h>
|
||||
|
@ -993,32 +994,20 @@ static struct drm_connector_helper_funcs exynos_dp_connector_helper_funcs = {
|
|||
.best_encoder = exynos_dp_best_encoder,
|
||||
};
|
||||
|
||||
static bool find_bridge(const char *compat, struct bridge_init *bridge)
|
||||
{
|
||||
bridge->client = NULL;
|
||||
bridge->node = of_find_compatible_node(NULL, NULL, compat);
|
||||
if (!bridge->node)
|
||||
return false;
|
||||
|
||||
bridge->client = of_find_i2c_device_by_node(bridge->node);
|
||||
if (!bridge->client)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* returns the number of bridges attached */
|
||||
static int exynos_drm_attach_lcd_bridge(struct drm_device *dev,
|
||||
static int exynos_drm_attach_lcd_bridge(struct exynos_dp_device *dp,
|
||||
struct drm_encoder *encoder)
|
||||
{
|
||||
struct bridge_init bridge;
|
||||
int ret;
|
||||
|
||||
if (find_bridge("nxp,ptn3460", &bridge)) {
|
||||
ret = ptn3460_init(dev, encoder, bridge.client, bridge.node);
|
||||
if (!ret)
|
||||
return 1;
|
||||
encoder->bridge = dp->bridge;
|
||||
dp->bridge->encoder = encoder;
|
||||
ret = drm_bridge_attach(encoder->dev, dp->bridge);
|
||||
if (ret) {
|
||||
DRM_ERROR("Failed to attach bridge to drm\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1032,9 +1021,11 @@ static int exynos_dp_create_connector(struct exynos_drm_display *display,
|
|||
dp->encoder = encoder;
|
||||
|
||||
/* Pre-empt DP connector creation if there's a bridge */
|
||||
ret = exynos_drm_attach_lcd_bridge(dp->drm_dev, encoder);
|
||||
if (ret)
|
||||
return 0;
|
||||
if (dp->bridge) {
|
||||
ret = exynos_drm_attach_lcd_bridge(dp, encoder);
|
||||
if (!ret)
|
||||
return 0;
|
||||
}
|
||||
|
||||
connector->polled = DRM_CONNECTOR_POLL_HPD;
|
||||
|
||||
|
@ -1241,7 +1232,7 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
|
|||
}
|
||||
}
|
||||
|
||||
if (!dp->panel) {
|
||||
if (!dp->panel && !dp->bridge) {
|
||||
ret = exynos_dp_dt_parse_panel(dp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -1325,7 +1316,7 @@ static const struct component_ops exynos_dp_ops = {
|
|||
static int exynos_dp_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *panel_node;
|
||||
struct device_node *panel_node, *bridge_node, *endpoint;
|
||||
struct exynos_dp_device *dp;
|
||||
int ret;
|
||||
|
||||
|
@ -1351,6 +1342,18 @@ static int exynos_dp_probe(struct platform_device *pdev)
|
|||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
|
||||
if (endpoint) {
|
||||
bridge_node = of_graph_get_remote_port_parent(endpoint);
|
||||
if (bridge_node) {
|
||||
dp->bridge = of_drm_find_bridge(bridge_node);
|
||||
of_node_put(bridge_node);
|
||||
if (!dp->bridge)
|
||||
return -EPROBE_DEFER;
|
||||
} else
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
ret = component_add(&pdev->dev, &exynos_dp_ops);
|
||||
if (ret)
|
||||
exynos_drm_component_del(&pdev->dev,
|
||||
|
|
|
@ -153,6 +153,7 @@ struct exynos_dp_device {
|
|||
struct drm_connector connector;
|
||||
struct drm_encoder *encoder;
|
||||
struct drm_panel *panel;
|
||||
struct drm_bridge *bridge;
|
||||
struct clk *clock;
|
||||
unsigned int irq;
|
||||
void __iomem *reg_base;
|
||||
|
|
|
@ -247,9 +247,9 @@ int hdmi_modeset_init(struct hdmi *hdmi,
|
|||
return 0;
|
||||
|
||||
fail:
|
||||
/* bridge/connector are normally destroyed by drm: */
|
||||
/* bridge is normally destroyed by drm: */
|
||||
if (hdmi->bridge) {
|
||||
hdmi->bridge->funcs->destroy(hdmi->bridge);
|
||||
hdmi_bridge_destroy(hdmi->bridge);
|
||||
hdmi->bridge = NULL;
|
||||
}
|
||||
if (hdmi->connector) {
|
||||
|
|
|
@ -146,6 +146,7 @@ void hdmi_audio_set_sample_rate(struct hdmi *hdmi, int rate);
|
|||
*/
|
||||
|
||||
struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi);
|
||||
void hdmi_bridge_destroy(struct drm_bridge *bridge);
|
||||
|
||||
/*
|
||||
* hdmi connector:
|
||||
|
|
|
@ -23,10 +23,9 @@ struct hdmi_bridge {
|
|||
};
|
||||
#define to_hdmi_bridge(x) container_of(x, struct hdmi_bridge, base)
|
||||
|
||||
static void hdmi_bridge_destroy(struct drm_bridge *bridge)
|
||||
void hdmi_bridge_destroy(struct drm_bridge *bridge)
|
||||
{
|
||||
struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
|
||||
drm_bridge_cleanup(bridge);
|
||||
kfree(hdmi_bridge);
|
||||
}
|
||||
|
||||
|
@ -200,7 +199,6 @@ static const struct drm_bridge_funcs hdmi_bridge_funcs = {
|
|||
.disable = hdmi_bridge_disable,
|
||||
.post_disable = hdmi_bridge_post_disable,
|
||||
.mode_set = hdmi_bridge_mode_set,
|
||||
.destroy = hdmi_bridge_destroy,
|
||||
};
|
||||
|
||||
|
||||
|
@ -220,8 +218,9 @@ struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi)
|
|||
hdmi_bridge->hdmi = hdmi;
|
||||
|
||||
bridge = &hdmi_bridge->base;
|
||||
bridge->funcs = &hdmi_bridge_funcs;
|
||||
|
||||
drm_bridge_init(hdmi->dev, bridge, &hdmi_bridge_funcs);
|
||||
drm_bridge_attach(hdmi->dev, bridge);
|
||||
|
||||
return bridge;
|
||||
|
||||
|
|
|
@ -19,8 +19,6 @@
|
|||
|
||||
#include <video/mipi_display.h>
|
||||
|
||||
#include <linux/host1x.h>
|
||||
|
||||
struct sharp_panel {
|
||||
struct drm_panel base;
|
||||
/* the datasheet refers to them as DSI-LINK1 and DSI-LINK2 */
|
||||
|
@ -41,6 +39,16 @@ static inline struct sharp_panel *to_sharp_panel(struct drm_panel *panel)
|
|||
return container_of(panel, struct sharp_panel, base);
|
||||
}
|
||||
|
||||
static void sharp_wait_frames(struct sharp_panel *sharp, unsigned int frames)
|
||||
{
|
||||
unsigned int refresh = drm_mode_vrefresh(sharp->mode);
|
||||
|
||||
if (WARN_ON(frames > refresh))
|
||||
return;
|
||||
|
||||
msleep(1000 / (refresh / frames));
|
||||
}
|
||||
|
||||
static int sharp_panel_write(struct sharp_panel *sharp, u16 offset, u8 value)
|
||||
{
|
||||
u8 payload[3] = { offset >> 8, offset & 0xff, value };
|
||||
|
@ -106,6 +114,8 @@ static int sharp_panel_unprepare(struct drm_panel *panel)
|
|||
if (!sharp->prepared)
|
||||
return 0;
|
||||
|
||||
sharp_wait_frames(sharp, 4);
|
||||
|
||||
err = mipi_dsi_dcs_set_display_off(sharp->link1);
|
||||
if (err < 0)
|
||||
dev_err(panel->dev, "failed to set display off: %d\n", err);
|
||||
|
@ -170,15 +180,13 @@ static int sharp_panel_prepare(struct drm_panel *panel)
|
|||
if (err < 0)
|
||||
return err;
|
||||
|
||||
usleep_range(10000, 20000);
|
||||
|
||||
err = mipi_dsi_dcs_soft_reset(sharp->link1);
|
||||
if (err < 0) {
|
||||
dev_err(panel->dev, "soft reset failed: %d\n", err);
|
||||
goto poweroff;
|
||||
}
|
||||
|
||||
msleep(120);
|
||||
/*
|
||||
* According to the datasheet, the panel needs around 10 ms to fully
|
||||
* power up. At least another 120 ms is required before exiting sleep
|
||||
* mode to make sure the panel is ready. Throw in another 20 ms for
|
||||
* good measure.
|
||||
*/
|
||||
msleep(150);
|
||||
|
||||
err = mipi_dsi_dcs_exit_sleep_mode(sharp->link1);
|
||||
if (err < 0) {
|
||||
|
@ -238,6 +246,9 @@ static int sharp_panel_prepare(struct drm_panel *panel)
|
|||
|
||||
sharp->prepared = true;
|
||||
|
||||
/* wait for 6 frames before continuing */
|
||||
sharp_wait_frames(sharp, 6);
|
||||
|
||||
return 0;
|
||||
|
||||
poweroff:
|
||||
|
|
|
@ -448,6 +448,34 @@ static const struct panel_desc auo_b133htn01 = {
|
|||
},
|
||||
};
|
||||
|
||||
static const struct drm_display_mode avic_tm070ddh03_mode = {
|
||||
.clock = 51200,
|
||||
.hdisplay = 1024,
|
||||
.hsync_start = 1024 + 160,
|
||||
.hsync_end = 1024 + 160 + 4,
|
||||
.htotal = 1024 + 160 + 4 + 156,
|
||||
.vdisplay = 600,
|
||||
.vsync_start = 600 + 17,
|
||||
.vsync_end = 600 + 17 + 1,
|
||||
.vtotal = 600 + 17 + 1 + 17,
|
||||
.vrefresh = 60,
|
||||
};
|
||||
|
||||
static const struct panel_desc avic_tm070ddh03 = {
|
||||
.modes = &avic_tm070ddh03_mode,
|
||||
.num_modes = 1,
|
||||
.bpc = 8,
|
||||
.size = {
|
||||
.width = 154,
|
||||
.height = 90,
|
||||
},
|
||||
.delay = {
|
||||
.prepare = 20,
|
||||
.enable = 200,
|
||||
.disable = 200,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct drm_display_mode chunghwa_claa101wa01a_mode = {
|
||||
.clock = 72070,
|
||||
.hdisplay = 1366,
|
||||
|
@ -566,6 +594,29 @@ static const struct panel_desc foxlink_fl500wvr00_a0t = {
|
|||
.bus_format = MEDIA_BUS_FMT_RGB888_1X24,
|
||||
};
|
||||
|
||||
static const struct drm_display_mode giantplus_gpg482739qs5_mode = {
|
||||
.clock = 9000,
|
||||
.hdisplay = 480,
|
||||
.hsync_start = 480 + 5,
|
||||
.hsync_end = 480 + 5 + 1,
|
||||
.htotal = 480 + 5 + 1 + 40,
|
||||
.vdisplay = 272,
|
||||
.vsync_start = 272 + 8,
|
||||
.vsync_end = 272 + 8 + 1,
|
||||
.vtotal = 272 + 8 + 1 + 8,
|
||||
.vrefresh = 60,
|
||||
};
|
||||
|
||||
static const struct panel_desc giantplus_gpg482739qs5 = {
|
||||
.modes = &giantplus_gpg482739qs5_mode,
|
||||
.num_modes = 1,
|
||||
.bpc = 8,
|
||||
.size = {
|
||||
.width = 95,
|
||||
.height = 54,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct drm_display_mode hannstar_hsd070pww1_mode = {
|
||||
.clock = 71100,
|
||||
.hdisplay = 1280,
|
||||
|
@ -744,6 +795,9 @@ static const struct of_device_id platform_of_match[] = {
|
|||
}, {
|
||||
.compatible = "auo,b133xtn01",
|
||||
.data = &auo_b133xtn01,
|
||||
}, {
|
||||
.compatible = "avic,tm070ddh03",
|
||||
.data = &avic_tm070ddh03,
|
||||
}, {
|
||||
.compatible = "chunghwa,claa101wa01a",
|
||||
.data = &chunghwa_claa101wa01a
|
||||
|
@ -762,6 +816,9 @@ static const struct of_device_id platform_of_match[] = {
|
|||
}, {
|
||||
.compatible = "foxlink,fl500wvr00-a0t",
|
||||
.data = &foxlink_fl500wvr00_a0t,
|
||||
}, {
|
||||
.compatible = "giantplus,gpg482739qs5",
|
||||
.data = &giantplus_gpg482739qs5
|
||||
}, {
|
||||
.compatible = "hannstar,hsd070pww1",
|
||||
.data = &hannstar_hsd070pww1,
|
||||
|
|
|
@ -91,6 +91,7 @@ struct sti_dvo {
|
|||
struct dvo_config *config;
|
||||
bool enabled;
|
||||
struct drm_encoder *encoder;
|
||||
struct drm_bridge *bridge;
|
||||
};
|
||||
|
||||
struct sti_dvo_connector {
|
||||
|
@ -272,19 +273,12 @@ static void sti_dvo_bridge_nope(struct drm_bridge *bridge)
|
|||
/* do nothing */
|
||||
}
|
||||
|
||||
static void sti_dvo_brigde_destroy(struct drm_bridge *bridge)
|
||||
{
|
||||
drm_bridge_cleanup(bridge);
|
||||
kfree(bridge);
|
||||
}
|
||||
|
||||
static const struct drm_bridge_funcs sti_dvo_bridge_funcs = {
|
||||
.pre_enable = sti_dvo_pre_enable,
|
||||
.enable = sti_dvo_bridge_nope,
|
||||
.disable = sti_dvo_disable,
|
||||
.post_disable = sti_dvo_bridge_nope,
|
||||
.mode_set = sti_dvo_set_mode,
|
||||
.destroy = sti_dvo_brigde_destroy,
|
||||
};
|
||||
|
||||
static int sti_dvo_connector_get_modes(struct drm_connector *connector)
|
||||
|
@ -416,8 +410,21 @@ static int sti_dvo_bind(struct device *dev, struct device *master, void *data)
|
|||
return -ENOMEM;
|
||||
|
||||
bridge->driver_private = dvo;
|
||||
drm_bridge_init(drm_dev, bridge, &sti_dvo_bridge_funcs);
|
||||
bridge->funcs = &sti_dvo_bridge_funcs;
|
||||
bridge->of_node = dvo->dev.of_node;
|
||||
err = drm_bridge_add(bridge);
|
||||
if (err) {
|
||||
DRM_ERROR("Failed to add bridge\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = drm_bridge_attach(drm_dev, bridge);
|
||||
if (err) {
|
||||
DRM_ERROR("Failed to attach bridge\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
dvo->bridge = bridge;
|
||||
encoder->bridge = bridge;
|
||||
connector->encoder = encoder;
|
||||
dvo->encoder = encoder;
|
||||
|
@ -446,7 +453,7 @@ static int sti_dvo_bind(struct device *dev, struct device *master, void *data)
|
|||
err_sysfs:
|
||||
drm_connector_unregister(drm_connector);
|
||||
err_connector:
|
||||
drm_bridge_cleanup(bridge);
|
||||
drm_bridge_remove(bridge);
|
||||
drm_connector_cleanup(drm_connector);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -454,7 +461,9 @@ err_connector:
|
|||
static void sti_dvo_unbind(struct device *dev,
|
||||
struct device *master, void *data)
|
||||
{
|
||||
/* do nothing */
|
||||
struct sti_dvo *dvo = dev_get_drvdata(dev);
|
||||
|
||||
drm_bridge_remove(dvo->bridge);
|
||||
}
|
||||
|
||||
static const struct component_ops sti_dvo_ops = {
|
||||
|
|
|
@ -508,19 +508,12 @@ static void sti_hda_bridge_nope(struct drm_bridge *bridge)
|
|||
/* do nothing */
|
||||
}
|
||||
|
||||
static void sti_hda_brigde_destroy(struct drm_bridge *bridge)
|
||||
{
|
||||
drm_bridge_cleanup(bridge);
|
||||
kfree(bridge);
|
||||
}
|
||||
|
||||
static const struct drm_bridge_funcs sti_hda_bridge_funcs = {
|
||||
.pre_enable = sti_hda_pre_enable,
|
||||
.enable = sti_hda_bridge_nope,
|
||||
.disable = sti_hda_disable,
|
||||
.post_disable = sti_hda_bridge_nope,
|
||||
.mode_set = sti_hda_set_mode,
|
||||
.destroy = sti_hda_brigde_destroy,
|
||||
};
|
||||
|
||||
static int sti_hda_connector_get_modes(struct drm_connector *connector)
|
||||
|
@ -664,7 +657,8 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data)
|
|||
return -ENOMEM;
|
||||
|
||||
bridge->driver_private = hda;
|
||||
drm_bridge_init(drm_dev, bridge, &sti_hda_bridge_funcs);
|
||||
bridge->funcs = &sti_hda_bridge_funcs;
|
||||
drm_bridge_attach(drm_dev, bridge);
|
||||
|
||||
encoder->bridge = bridge;
|
||||
connector->encoder = encoder;
|
||||
|
@ -693,7 +687,6 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data)
|
|||
err_sysfs:
|
||||
drm_connector_unregister(drm_connector);
|
||||
err_connector:
|
||||
drm_bridge_cleanup(bridge);
|
||||
drm_connector_cleanup(drm_connector);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
|
@ -463,19 +463,12 @@ static void sti_hdmi_bridge_nope(struct drm_bridge *bridge)
|
|||
/* do nothing */
|
||||
}
|
||||
|
||||
static void sti_hdmi_brigde_destroy(struct drm_bridge *bridge)
|
||||
{
|
||||
drm_bridge_cleanup(bridge);
|
||||
kfree(bridge);
|
||||
}
|
||||
|
||||
static const struct drm_bridge_funcs sti_hdmi_bridge_funcs = {
|
||||
.pre_enable = sti_hdmi_pre_enable,
|
||||
.enable = sti_hdmi_bridge_nope,
|
||||
.disable = sti_hdmi_disable,
|
||||
.post_disable = sti_hdmi_bridge_nope,
|
||||
.mode_set = sti_hdmi_set_mode,
|
||||
.destroy = sti_hdmi_brigde_destroy,
|
||||
};
|
||||
|
||||
static int sti_hdmi_connector_get_modes(struct drm_connector *connector)
|
||||
|
@ -635,7 +628,8 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
|
|||
goto err_adapt;
|
||||
|
||||
bridge->driver_private = hdmi;
|
||||
drm_bridge_init(drm_dev, bridge, &sti_hdmi_bridge_funcs);
|
||||
bridge->funcs = &sti_hdmi_bridge_funcs;
|
||||
drm_bridge_attach(drm_dev, bridge);
|
||||
|
||||
encoder->bridge = bridge;
|
||||
connector->encoder = encoder;
|
||||
|
@ -667,7 +661,6 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
|
|||
err_sysfs:
|
||||
drm_connector_unregister(drm_connector);
|
||||
err_connector:
|
||||
drm_bridge_cleanup(bridge);
|
||||
drm_connector_cleanup(drm_connector);
|
||||
err_adapt:
|
||||
put_device(&hdmi->ddc_adapt->dev);
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#define _DRM_BRIDGE_PTN3460_H_
|
||||
|
||||
struct drm_device;
|
||||
struct drm_bridge;
|
||||
struct drm_encoder;
|
||||
struct i2c_client;
|
||||
struct device_node;
|
||||
|
@ -23,6 +24,9 @@ struct device_node;
|
|||
|
||||
int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder,
|
||||
struct i2c_client *client, struct device_node *node);
|
||||
|
||||
void ptn3460_destroy(struct drm_bridge *bridge);
|
||||
|
||||
#else
|
||||
|
||||
static inline int ptn3460_init(struct drm_device *dev,
|
||||
|
@ -32,6 +36,10 @@ static inline int ptn3460_init(struct drm_device *dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline void ptn3460_destroy(struct drm_bridge *bridge)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -868,15 +868,16 @@ struct drm_plane {
|
|||
|
||||
/**
|
||||
* struct drm_bridge_funcs - drm_bridge control functions
|
||||
* @attach: Called during drm_bridge_attach
|
||||
* @mode_fixup: Try to fixup (or reject entirely) proposed mode for this bridge
|
||||
* @disable: Called right before encoder prepare, disables the bridge
|
||||
* @post_disable: Called right after encoder prepare, for lockstepped disable
|
||||
* @mode_set: Set this mode to the bridge
|
||||
* @pre_enable: Called right before encoder commit, for lockstepped commit
|
||||
* @enable: Called right after encoder commit, enables the bridge
|
||||
* @destroy: make object go away
|
||||
*/
|
||||
struct drm_bridge_funcs {
|
||||
int (*attach)(struct drm_bridge *bridge);
|
||||
bool (*mode_fixup)(struct drm_bridge *bridge,
|
||||
const struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode);
|
||||
|
@ -887,22 +888,24 @@ struct drm_bridge_funcs {
|
|||
struct drm_display_mode *adjusted_mode);
|
||||
void (*pre_enable)(struct drm_bridge *bridge);
|
||||
void (*enable)(struct drm_bridge *bridge);
|
||||
void (*destroy)(struct drm_bridge *bridge);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct drm_bridge - central DRM bridge control structure
|
||||
* @dev: DRM device this bridge belongs to
|
||||
* @head: list management
|
||||
* @of_node: device node pointer to the bridge
|
||||
* @list: to keep track of all added bridges
|
||||
* @base: base mode object
|
||||
* @funcs: control functions
|
||||
* @driver_private: pointer to the bridge driver's internal context
|
||||
*/
|
||||
struct drm_bridge {
|
||||
struct drm_device *dev;
|
||||
struct list_head head;
|
||||
|
||||
struct drm_mode_object base;
|
||||
struct drm_encoder *encoder;
|
||||
#ifdef CONFIG_OF
|
||||
struct device_node *of_node;
|
||||
#endif
|
||||
struct list_head list;
|
||||
|
||||
const struct drm_bridge_funcs *funcs;
|
||||
void *driver_private;
|
||||
|
@ -1007,7 +1010,6 @@ struct drm_mode_group {
|
|||
uint32_t num_crtcs;
|
||||
uint32_t num_encoders;
|
||||
uint32_t num_connectors;
|
||||
uint32_t num_bridges;
|
||||
|
||||
/* list of object IDs for this group */
|
||||
uint32_t *id_list;
|
||||
|
@ -1026,8 +1028,6 @@ struct drm_mode_group {
|
|||
* @fb_list: list of framebuffers available
|
||||
* @num_connector: number of connectors on this device
|
||||
* @connector_list: list of connector objects
|
||||
* @num_bridge: number of bridges on this device
|
||||
* @bridge_list: list of bridge objects
|
||||
* @num_encoder: number of encoders on this device
|
||||
* @encoder_list: list of encoder objects
|
||||
* @num_overlay_plane: number of overlay planes on this device
|
||||
|
@ -1072,8 +1072,6 @@ struct drm_mode_config {
|
|||
|
||||
int num_connector;
|
||||
struct list_head connector_list;
|
||||
int num_bridge;
|
||||
struct list_head bridge_list;
|
||||
int num_encoder;
|
||||
struct list_head encoder_list;
|
||||
|
||||
|
@ -1222,9 +1220,10 @@ extern unsigned int drm_connector_index(struct drm_connector *connector);
|
|||
/* helper to unplug all connectors from sysfs for device */
|
||||
extern void drm_connector_unplug_all(struct drm_device *dev);
|
||||
|
||||
extern int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge,
|
||||
const struct drm_bridge_funcs *funcs);
|
||||
extern void drm_bridge_cleanup(struct drm_bridge *bridge);
|
||||
extern int drm_bridge_add(struct drm_bridge *bridge);
|
||||
extern void drm_bridge_remove(struct drm_bridge *bridge);
|
||||
extern struct drm_bridge *of_drm_find_bridge(struct device_node *np);
|
||||
extern int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge);
|
||||
|
||||
extern int drm_encoder_init(struct drm_device *dev,
|
||||
struct drm_encoder *encoder,
|
||||
|
|
Loading…
Reference in New Issue