diff options
author | Dave Airlie <airlied@gmail.com> | 2015-01-28 20:29:35 -0500 |
---|---|---|
committer | Dave Airlie <airlied@gmail.com> | 2015-01-28 20:29:35 -0500 |
commit | 7b83741bf76caad72bc8a701c26dde8d6751ff0f (patch) | |
tree | 2a751157e734c1aaf2acdde48ef3645bd951ac08 | |
parent | 21773f16f2cb3c056051c679da542f0b494252e2 (diff) | |
parent | b5217bf4692218d202d3d2cd772864fa1e10be4d (diff) |
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
...
25 files changed, 531 insertions, 294 deletions
diff --git a/Documentation/devicetree/bindings/panel/avic,tm070ddh03.txt b/Documentation/devicetree/bindings/panel/avic,tm070ddh03.txt new file mode 100644 index 000000000000..b6f2f3e8f44e --- /dev/null +++ b/Documentation/devicetree/bindings/panel/avic,tm070ddh03.txt | |||
@@ -0,0 +1,7 @@ | |||
1 | Shanghai AVIC Optoelectronics 7" 1024x600 color TFT-LCD panel | ||
2 | |||
3 | Required properties: | ||
4 | - compatible: should be "avic,tm070ddh03" | ||
5 | |||
6 | This binding is compatible with the simple-panel binding, which is specified | ||
7 | in simple-panel.txt in this directory. | ||
diff --git a/Documentation/devicetree/bindings/panel/giantplus,gpg482739qs5.txt b/Documentation/devicetree/bindings/panel/giantplus,gpg482739qs5.txt new file mode 100644 index 000000000000..24b0b624434b --- /dev/null +++ b/Documentation/devicetree/bindings/panel/giantplus,gpg482739qs5.txt | |||
@@ -0,0 +1,7 @@ | |||
1 | GiantPlus GPG48273QS5 4.3" (480x272) WQVGA TFT LCD panel | ||
2 | |||
3 | Required properties: | ||
4 | - compatible: should be "giantplus,gpg48273qs5" | ||
5 | |||
6 | This binding is compatible with the simple-panel binding, which is specified | ||
7 | in simple-panel.txt in this directory. | ||
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index b1df0ad1306c..c0333a97c47a 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt | |||
@@ -23,6 +23,7 @@ armadeus ARMadeus Systems SARL | |||
23 | atmel Atmel Corporation | 23 | atmel Atmel Corporation |
24 | auo AU Optronics Corporation | 24 | auo AU Optronics Corporation |
25 | avago Avago Technologies | 25 | avago Avago Technologies |
26 | avic Shanghai AVIC Optoelectronics Co., Ltd. | ||
26 | bosch Bosch Sensortec GmbH | 27 | bosch Bosch Sensortec GmbH |
27 | brcm Broadcom Corporation | 28 | brcm Broadcom Corporation |
28 | buffalo Buffalo, Inc. | 29 | buffalo Buffalo, Inc. |
@@ -62,6 +63,7 @@ fsl Freescale Semiconductor | |||
62 | GEFanuc GE Fanuc Intelligent Platforms Embedded Systems, Inc. | 63 | GEFanuc GE Fanuc Intelligent Platforms Embedded Systems, Inc. |
63 | gef GE Fanuc Intelligent Platforms Embedded Systems, Inc. | 64 | gef GE Fanuc Intelligent Platforms Embedded Systems, Inc. |
64 | geniatech Geniatech, Inc. | 65 | geniatech Geniatech, Inc. |
66 | giantplus Giantplus Technology Co., Ltd. | ||
65 | globalscale Globalscale Technologies, Inc. | 67 | globalscale Globalscale Technologies, Inc. |
66 | gmt Global Mixed-mode Technology, Inc. | 68 | gmt Global Mixed-mode Technology, Inc. |
67 | google Google, Inc. | 69 | google Google, Inc. |
@@ -119,6 +121,7 @@ nxp NXP Semiconductors | |||
119 | onnn ON Semiconductor Corp. | 121 | onnn ON Semiconductor Corp. |
120 | opencores OpenCores.org | 122 | opencores OpenCores.org |
121 | panasonic Panasonic Corporation | 123 | panasonic Panasonic Corporation |
124 | parade Parade Technologies Inc. | ||
122 | pericom Pericom Technology Inc. | 125 | pericom Pericom Technology Inc. |
123 | phytec PHYTEC Messtechnik GmbH | 126 | phytec PHYTEC Messtechnik GmbH |
124 | picochip Picochip Ltd | 127 | picochip Picochip Ltd |
diff --git a/Documentation/devicetree/bindings/video/bridge/ps8622.txt b/Documentation/devicetree/bindings/video/bridge/ps8622.txt new file mode 100644 index 000000000000..c989c3807f2b --- /dev/null +++ b/Documentation/devicetree/bindings/video/bridge/ps8622.txt | |||
@@ -0,0 +1,31 @@ | |||
1 | ps8622-bridge bindings | ||
2 | |||
3 | Required properties: | ||
4 | - compatible: "parade,ps8622" or "parade,ps8625" | ||
5 | - reg: first i2c address of the bridge | ||
6 | - sleep-gpios: OF device-tree gpio specification for PD_ pin. | ||
7 | - reset-gpios: OF device-tree gpio specification for RST_ pin. | ||
8 | |||
9 | Optional properties: | ||
10 | - lane-count: number of DP lanes to use | ||
11 | - use-external-pwm: backlight will be controlled by an external PWM | ||
12 | - video interfaces: Device node can contain video interface port | ||
13 | nodes for panel according to [1]. | ||
14 | |||
15 | [1]: Documentation/devicetree/bindings/media/video-interfaces.txt | ||
16 | |||
17 | Example: | ||
18 | lvds-bridge@48 { | ||
19 | compatible = "parade,ps8622"; | ||
20 | reg = <0x48>; | ||
21 | sleep-gpios = <&gpc3 6 1 0 0>; | ||
22 | reset-gpios = <&gpc3 1 1 0 0>; | ||
23 | lane-count = <1>; | ||
24 | ports { | ||
25 | port@0 { | ||
26 | bridge_out: endpoint { | ||
27 | remote-endpoint = <&panel_in>; | ||
28 | }; | ||
29 | }; | ||
30 | }; | ||
31 | }; | ||
diff --git a/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt b/Documentation/devicetree/bindings/video/bridge/ptn3460.txt index 52b93b2c6748..361971ba104d 100644 --- a/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt +++ b/Documentation/devicetree/bindings/video/bridge/ptn3460.txt | |||
@@ -3,8 +3,8 @@ ptn3460 bridge bindings | |||
3 | Required properties: | 3 | Required properties: |
4 | - compatible: "nxp,ptn3460" | 4 | - compatible: "nxp,ptn3460" |
5 | - reg: i2c address of the bridge | 5 | - reg: i2c address of the bridge |
6 | - powerdown-gpio: OF device-tree gpio specification | 6 | - powerdown-gpio: OF device-tree gpio specification for PD_N pin. |
7 | - reset-gpio: OF device-tree gpio specification | 7 | - reset-gpio: OF device-tree gpio specification for RST_N pin. |
8 | - edid-emulation: The EDID emulation entry to use | 8 | - edid-emulation: The EDID emulation entry to use |
9 | +-------+------------+------------------+ | 9 | +-------+------------+------------------+ |
10 | | Value | Resolution | Description | | 10 | | Value | Resolution | Description | |
@@ -17,6 +17,11 @@ Required properties: | |||
17 | | 6 | 1600x900 | ChiMei M215HGE | | 17 | | 6 | 1600x900 | ChiMei M215HGE | |
18 | +-------+------------+------------------+ | 18 | +-------+------------+------------------+ |
19 | 19 | ||
20 | - video interfaces: Device node can contain video interface port | ||
21 | nodes for panel according to [1]. | ||
22 | |||
23 | [1]: Documentation/devicetree/bindings/media/video-interfaces.txt | ||
24 | |||
20 | Example: | 25 | Example: |
21 | lvds-bridge@20 { | 26 | lvds-bridge@20 { |
22 | compatible = "nxp,ptn3460"; | 27 | compatible = "nxp,ptn3460"; |
@@ -24,4 +29,11 @@ Example: | |||
24 | powerdown-gpio = <&gpy2 5 1 0 0>; | 29 | powerdown-gpio = <&gpy2 5 1 0 0>; |
25 | reset-gpio = <&gpx1 5 1 0 0>; | 30 | reset-gpio = <&gpx1 5 1 0 0>; |
26 | edid-emulation = <5>; | 31 | edid-emulation = <5>; |
32 | ports { | ||
33 | port@0 { | ||
34 | bridge_out: endpoint { | ||
35 | remote-endpoint = <&panel_in>; | ||
36 | }; | ||
37 | }; | ||
38 | }; | ||
27 | }; | 39 | }; |
diff --git a/Documentation/devicetree/bindings/video/exynos_dp.txt b/Documentation/devicetree/bindings/video/exynos_dp.txt index 53dbccfa80ca..7a3a9cdb86ab 100644 --- a/Documentation/devicetree/bindings/video/exynos_dp.txt +++ b/Documentation/devicetree/bindings/video/exynos_dp.txt | |||
@@ -66,6 +66,10 @@ Optional properties for dp-controller: | |||
66 | Hotplug detect GPIO. | 66 | Hotplug detect GPIO. |
67 | Indicates which GPIO should be used for hotplug | 67 | Indicates which GPIO should be used for hotplug |
68 | detection | 68 | detection |
69 | -video interfaces: Device node can contain video interface port | ||
70 | nodes according to [1]. | ||
71 | |||
72 | [1]: Documentation/devicetree/bindings/media/video-interfaces.txt | ||
69 | 73 | ||
70 | Example: | 74 | Example: |
71 | 75 | ||
@@ -105,4 +109,12 @@ Board Specific portion: | |||
105 | vsync-len = <6>; | 109 | vsync-len = <6>; |
106 | }; | 110 | }; |
107 | }; | 111 | }; |
112 | |||
113 | ports { | ||
114 | port@0 { | ||
115 | dp_out: endpoint { | ||
116 | remote-endpoint = <&bridge_in>; | ||
117 | }; | ||
118 | }; | ||
119 | }; | ||
108 | }; | 120 | }; |
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index cf0eed8208b5..2c239b99de64 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile | |||
@@ -14,7 +14,7 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \ | |||
14 | drm_info.o drm_debugfs.o drm_encoder_slave.o \ | 14 | drm_info.o drm_debugfs.o drm_encoder_slave.o \ |
15 | drm_trace_points.o drm_global.o drm_prime.o \ | 15 | drm_trace_points.o drm_global.o drm_prime.o \ |
16 | drm_rect.o drm_vma_manager.o drm_flip_work.o \ | 16 | drm_rect.o drm_vma_manager.o drm_flip_work.o \ |
17 | drm_modeset_lock.o drm_atomic.o | 17 | drm_modeset_lock.o drm_atomic.o drm_bridge.o |
18 | 18 | ||
19 | drm-$(CONFIG_COMPAT) += drm_ioc32.o | 19 | drm-$(CONFIG_COMPAT) += drm_ioc32.o |
20 | drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o | 20 | drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o |
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index b70f3c8d4e8a..f38bbcdf929b 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig | |||
@@ -1,10 +1,13 @@ | |||
1 | config DRM_PTN3460 | 1 | config DRM_DW_HDMI |
2 | tristate "PTN3460 DP/LVDS bridge" | 2 | tristate |
3 | depends on DRM | 3 | depends on DRM |
4 | select DRM_KMS_HELPER | 4 | select DRM_KMS_HELPER |
5 | ---help--- | ||
6 | 5 | ||
7 | config DRM_DW_HDMI | 6 | config DRM_PTN3460 |
8 | tristate | 7 | tristate "PTN3460 DP/LVDS bridge" |
9 | depends on DRM | 8 | depends on DRM |
9 | depends on OF | ||
10 | select DRM_KMS_HELPER | 10 | select DRM_KMS_HELPER |
11 | select DRM_PANEL | ||
12 | ---help--- | ||
13 | ptn3460 eDP-LVDS bridge chip driver. | ||
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c index 6ea000504173..cd6a70647e32 100644 --- a/drivers/gpu/drm/bridge/dw_hdmi.c +++ b/drivers/gpu/drm/bridge/dw_hdmi.c | |||
@@ -1373,12 +1373,6 @@ static void dw_hdmi_bridge_enable(struct drm_bridge *bridge) | |||
1373 | dw_hdmi_poweron(hdmi); | 1373 | dw_hdmi_poweron(hdmi); |
1374 | } | 1374 | } |
1375 | 1375 | ||
1376 | static void dw_hdmi_bridge_destroy(struct drm_bridge *bridge) | ||
1377 | { | ||
1378 | drm_bridge_cleanup(bridge); | ||
1379 | kfree(bridge); | ||
1380 | } | ||
1381 | |||
1382 | static void dw_hdmi_bridge_nop(struct drm_bridge *bridge) | 1376 | static void dw_hdmi_bridge_nop(struct drm_bridge *bridge) |
1383 | { | 1377 | { |
1384 | /* do nothing */ | 1378 | /* do nothing */ |
@@ -1468,7 +1462,6 @@ struct drm_bridge_funcs dw_hdmi_bridge_funcs = { | |||
1468 | .post_disable = dw_hdmi_bridge_nop, | 1462 | .post_disable = dw_hdmi_bridge_nop, |
1469 | .mode_set = dw_hdmi_bridge_mode_set, | 1463 | .mode_set = dw_hdmi_bridge_mode_set, |
1470 | .mode_fixup = dw_hdmi_bridge_mode_fixup, | 1464 | .mode_fixup = dw_hdmi_bridge_mode_fixup, |
1471 | .destroy = dw_hdmi_bridge_destroy, | ||
1472 | }; | 1465 | }; |
1473 | 1466 | ||
1474 | static irqreturn_t dw_hdmi_hardirq(int irq, void *dev_id) | 1467 | 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) | |||
1531 | 1524 | ||
1532 | hdmi->bridge = bridge; | 1525 | hdmi->bridge = bridge; |
1533 | bridge->driver_private = hdmi; | 1526 | bridge->driver_private = hdmi; |
1534 | 1527 | bridge->funcs = &dw_hdmi_bridge_funcs; | |
1535 | ret = drm_bridge_init(drm, bridge, &dw_hdmi_bridge_funcs); | 1528 | ret = drm_bridge_attach(drm, bridge); |
1536 | if (ret) { | 1529 | if (ret) { |
1537 | DRM_ERROR("Failed to initialize bridge with drm\n"); | 1530 | DRM_ERROR("Failed to initialize bridge with drm\n"); |
1538 | return -EINVAL; | 1531 | return -EINVAL; |
@@ -1649,7 +1642,7 @@ int dw_hdmi_bind(struct device *dev, struct device *master, | |||
1649 | dw_hdmi_irq, IRQF_SHARED, | 1642 | dw_hdmi_irq, IRQF_SHARED, |
1650 | dev_name(dev), hdmi); | 1643 | dev_name(dev), hdmi); |
1651 | if (ret) | 1644 | if (ret) |
1652 | return ret; | 1645 | goto err_iahb; |
1653 | 1646 | ||
1654 | /* | 1647 | /* |
1655 | * To prevent overflows in HDMI_IH_FC_STAT2, set the clk regenerator | 1648 | * To prevent overflows in HDMI_IH_FC_STAT2, set the clk regenerator |
diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c index d466696ed5e8..826833e396f0 100644 --- a/drivers/gpu/drm/bridge/ptn3460.c +++ b/drivers/gpu/drm/bridge/ptn3460.c | |||
@@ -13,20 +13,23 @@ | |||
13 | * GNU General Public License for more details. | 13 | * GNU General Public License for more details. |
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/gpio.h> | ||
18 | #include <linux/i2c.h> | ||
16 | #include <linux/module.h> | 19 | #include <linux/module.h> |
17 | #include <linux/of.h> | 20 | #include <linux/of.h> |
18 | #include <linux/of_gpio.h> | 21 | #include <linux/of_gpio.h> |
19 | #include <linux/i2c.h> | 22 | #include <linux/of_graph.h> |
20 | #include <linux/gpio.h> | ||
21 | #include <linux/delay.h> | ||
22 | 23 | ||
23 | #include "drmP.h" | 24 | #include <drm/drm_panel.h> |
24 | #include "drm_edid.h" | ||
25 | #include "drm_crtc.h" | ||
26 | #include "drm_crtc_helper.h" | ||
27 | 25 | ||
28 | #include "bridge/ptn3460.h" | 26 | #include "bridge/ptn3460.h" |
29 | 27 | ||
28 | #include "drm_crtc.h" | ||
29 | #include "drm_crtc_helper.h" | ||
30 | #include "drm_edid.h" | ||
31 | #include "drmP.h" | ||
32 | |||
30 | #define PTN3460_EDID_ADDR 0x0 | 33 | #define PTN3460_EDID_ADDR 0x0 |
31 | #define PTN3460_EDID_EMULATION_ADDR 0x84 | 34 | #define PTN3460_EDID_EMULATION_ADDR 0x84 |
32 | #define PTN3460_EDID_ENABLE_EMULATION 0 | 35 | #define PTN3460_EDID_ENABLE_EMULATION 0 |
@@ -36,15 +39,27 @@ | |||
36 | struct ptn3460_bridge { | 39 | struct ptn3460_bridge { |
37 | struct drm_connector connector; | 40 | struct drm_connector connector; |
38 | struct i2c_client *client; | 41 | struct i2c_client *client; |
39 | struct drm_encoder *encoder; | 42 | struct drm_bridge bridge; |
40 | struct drm_bridge *bridge; | ||
41 | struct edid *edid; | 43 | struct edid *edid; |
42 | int gpio_pd_n; | 44 | struct drm_panel *panel; |
43 | int gpio_rst_n; | 45 | struct gpio_desc *gpio_pd_n; |
46 | struct gpio_desc *gpio_rst_n; | ||
44 | u32 edid_emulation; | 47 | u32 edid_emulation; |
45 | bool enabled; | 48 | bool enabled; |
46 | }; | 49 | }; |
47 | 50 | ||
51 | static inline struct ptn3460_bridge * | ||
52 | bridge_to_ptn3460(struct drm_bridge *bridge) | ||
53 | { | ||
54 | return container_of(bridge, struct ptn3460_bridge, bridge); | ||
55 | } | ||
56 | |||
57 | static inline struct ptn3460_bridge * | ||
58 | connector_to_ptn3460(struct drm_connector *connector) | ||
59 | { | ||
60 | return container_of(connector, struct ptn3460_bridge, connector); | ||
61 | } | ||
62 | |||
48 | static int ptn3460_read_bytes(struct ptn3460_bridge *ptn_bridge, char addr, | 63 | static int ptn3460_read_bytes(struct ptn3460_bridge *ptn_bridge, char addr, |
49 | u8 *buf, int len) | 64 | u8 *buf, int len) |
50 | { | 65 | { |
@@ -92,7 +107,7 @@ static int ptn3460_select_edid(struct ptn3460_bridge *ptn_bridge) | |||
92 | ret = ptn3460_write_byte(ptn_bridge, PTN3460_EDID_SRAM_LOAD_ADDR, | 107 | ret = ptn3460_write_byte(ptn_bridge, PTN3460_EDID_SRAM_LOAD_ADDR, |
93 | ptn_bridge->edid_emulation); | 108 | ptn_bridge->edid_emulation); |
94 | if (ret) { | 109 | if (ret) { |
95 | DRM_ERROR("Failed to transfer edid to sram, ret=%d\n", ret); | 110 | DRM_ERROR("Failed to transfer EDID to sram, ret=%d\n", ret); |
96 | return ret; | 111 | return ret; |
97 | } | 112 | } |
98 | 113 | ||
@@ -102,7 +117,7 @@ static int ptn3460_select_edid(struct ptn3460_bridge *ptn_bridge) | |||
102 | 117 | ||
103 | ret = ptn3460_write_byte(ptn_bridge, PTN3460_EDID_EMULATION_ADDR, val); | 118 | ret = ptn3460_write_byte(ptn_bridge, PTN3460_EDID_EMULATION_ADDR, val); |
104 | if (ret) { | 119 | if (ret) { |
105 | DRM_ERROR("Failed to write edid value, ret=%d\n", ret); | 120 | DRM_ERROR("Failed to write EDID value, ret=%d\n", ret); |
106 | return ret; | 121 | return ret; |
107 | } | 122 | } |
108 | 123 | ||
@@ -111,19 +126,21 @@ static int ptn3460_select_edid(struct ptn3460_bridge *ptn_bridge) | |||
111 | 126 | ||
112 | static void ptn3460_pre_enable(struct drm_bridge *bridge) | 127 | static void ptn3460_pre_enable(struct drm_bridge *bridge) |
113 | { | 128 | { |
114 | struct ptn3460_bridge *ptn_bridge = bridge->driver_private; | 129 | struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge); |
115 | int ret; | 130 | int ret; |
116 | 131 | ||
117 | if (ptn_bridge->enabled) | 132 | if (ptn_bridge->enabled) |
118 | return; | 133 | return; |
119 | 134 | ||
120 | if (gpio_is_valid(ptn_bridge->gpio_pd_n)) | 135 | gpiod_set_value(ptn_bridge->gpio_pd_n, 1); |
121 | gpio_set_value(ptn_bridge->gpio_pd_n, 1); | 136 | |
137 | gpiod_set_value(ptn_bridge->gpio_rst_n, 0); | ||
138 | usleep_range(10, 20); | ||
139 | gpiod_set_value(ptn_bridge->gpio_rst_n, 1); | ||
122 | 140 | ||
123 | if (gpio_is_valid(ptn_bridge->gpio_rst_n)) { | 141 | if (drm_panel_prepare(ptn_bridge->panel)) { |
124 | gpio_set_value(ptn_bridge->gpio_rst_n, 0); | 142 | DRM_ERROR("failed to prepare panel\n"); |
125 | udelay(10); | 143 | return; |
126 | gpio_set_value(ptn_bridge->gpio_rst_n, 1); | ||
127 | } | 144 | } |
128 | 145 | ||
129 | /* | 146 | /* |
@@ -135,73 +152,67 @@ static void ptn3460_pre_enable(struct drm_bridge *bridge) | |||
135 | 152 | ||
136 | ret = ptn3460_select_edid(ptn_bridge); | 153 | ret = ptn3460_select_edid(ptn_bridge); |
137 | if (ret) | 154 | if (ret) |
138 | DRM_ERROR("Select edid failed ret=%d\n", ret); | 155 | DRM_ERROR("Select EDID failed ret=%d\n", ret); |
139 | 156 | ||
140 | ptn_bridge->enabled = true; | 157 | ptn_bridge->enabled = true; |
141 | } | 158 | } |
142 | 159 | ||
143 | static void ptn3460_enable(struct drm_bridge *bridge) | 160 | static void ptn3460_enable(struct drm_bridge *bridge) |
144 | { | 161 | { |
162 | struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge); | ||
163 | |||
164 | if (drm_panel_enable(ptn_bridge->panel)) { | ||
165 | DRM_ERROR("failed to enable panel\n"); | ||
166 | return; | ||
167 | } | ||
145 | } | 168 | } |
146 | 169 | ||
147 | static void ptn3460_disable(struct drm_bridge *bridge) | 170 | static void ptn3460_disable(struct drm_bridge *bridge) |
148 | { | 171 | { |
149 | struct ptn3460_bridge *ptn_bridge = bridge->driver_private; | 172 | struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge); |
150 | 173 | ||
151 | if (!ptn_bridge->enabled) | 174 | if (!ptn_bridge->enabled) |
152 | return; | 175 | return; |
153 | 176 | ||
154 | ptn_bridge->enabled = false; | 177 | ptn_bridge->enabled = false; |
155 | 178 | ||
156 | if (gpio_is_valid(ptn_bridge->gpio_rst_n)) | 179 | if (drm_panel_disable(ptn_bridge->panel)) { |
157 | gpio_set_value(ptn_bridge->gpio_rst_n, 1); | 180 | DRM_ERROR("failed to disable panel\n"); |
181 | return; | ||
182 | } | ||
158 | 183 | ||
159 | if (gpio_is_valid(ptn_bridge->gpio_pd_n)) | 184 | gpiod_set_value(ptn_bridge->gpio_rst_n, 1); |
160 | gpio_set_value(ptn_bridge->gpio_pd_n, 0); | 185 | gpiod_set_value(ptn_bridge->gpio_pd_n, 0); |
161 | } | 186 | } |
162 | 187 | ||
163 | static void ptn3460_post_disable(struct drm_bridge *bridge) | 188 | static void ptn3460_post_disable(struct drm_bridge *bridge) |
164 | { | 189 | { |
165 | } | 190 | struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge); |
166 | 191 | ||
167 | void ptn3460_bridge_destroy(struct drm_bridge *bridge) | 192 | if (drm_panel_unprepare(ptn_bridge->panel)) { |
168 | { | 193 | DRM_ERROR("failed to unprepare panel\n"); |
169 | struct ptn3460_bridge *ptn_bridge = bridge->driver_private; | 194 | return; |
170 | 195 | } | |
171 | drm_bridge_cleanup(bridge); | ||
172 | if (gpio_is_valid(ptn_bridge->gpio_pd_n)) | ||
173 | gpio_free(ptn_bridge->gpio_pd_n); | ||
174 | if (gpio_is_valid(ptn_bridge->gpio_rst_n)) | ||
175 | gpio_free(ptn_bridge->gpio_rst_n); | ||
176 | /* Nothing else to free, we've got devm allocated memory */ | ||
177 | } | 196 | } |
178 | 197 | ||
179 | struct drm_bridge_funcs ptn3460_bridge_funcs = { | 198 | static int ptn3460_get_modes(struct drm_connector *connector) |
180 | .pre_enable = ptn3460_pre_enable, | ||
181 | .enable = ptn3460_enable, | ||
182 | .disable = ptn3460_disable, | ||
183 | .post_disable = ptn3460_post_disable, | ||
184 | .destroy = ptn3460_bridge_destroy, | ||
185 | }; | ||
186 | |||
187 | int ptn3460_get_modes(struct drm_connector *connector) | ||
188 | { | 199 | { |
189 | struct ptn3460_bridge *ptn_bridge; | 200 | struct ptn3460_bridge *ptn_bridge; |
190 | u8 *edid; | 201 | u8 *edid; |
191 | int ret, num_modes; | 202 | int ret, num_modes = 0; |
192 | bool power_off; | 203 | bool power_off; |
193 | 204 | ||
194 | ptn_bridge = container_of(connector, struct ptn3460_bridge, connector); | 205 | ptn_bridge = connector_to_ptn3460(connector); |
195 | 206 | ||
196 | if (ptn_bridge->edid) | 207 | if (ptn_bridge->edid) |
197 | return drm_add_edid_modes(connector, ptn_bridge->edid); | 208 | return drm_add_edid_modes(connector, ptn_bridge->edid); |
198 | 209 | ||
199 | power_off = !ptn_bridge->enabled; | 210 | power_off = !ptn_bridge->enabled; |
200 | ptn3460_pre_enable(ptn_bridge->bridge); | 211 | ptn3460_pre_enable(&ptn_bridge->bridge); |
201 | 212 | ||
202 | edid = kmalloc(EDID_LENGTH, GFP_KERNEL); | 213 | edid = kmalloc(EDID_LENGTH, GFP_KERNEL); |
203 | if (!edid) { | 214 | if (!edid) { |
204 | DRM_ERROR("Failed to allocate edid\n"); | 215 | DRM_ERROR("Failed to allocate EDID\n"); |
205 | return 0; | 216 | return 0; |
206 | } | 217 | } |
207 | 218 | ||
@@ -209,7 +220,6 @@ int ptn3460_get_modes(struct drm_connector *connector) | |||
209 | EDID_LENGTH); | 220 | EDID_LENGTH); |
210 | if (ret) { | 221 | if (ret) { |
211 | kfree(edid); | 222 | kfree(edid); |
212 | num_modes = 0; | ||
213 | goto out; | 223 | goto out; |
214 | } | 224 | } |
215 | 225 | ||
@@ -220,124 +230,188 @@ int ptn3460_get_modes(struct drm_connector *connector) | |||
220 | 230 | ||
221 | out: | 231 | out: |
222 | if (power_off) | 232 | if (power_off) |
223 | ptn3460_disable(ptn_bridge->bridge); | 233 | ptn3460_disable(&ptn_bridge->bridge); |
224 | 234 | ||
225 | return num_modes; | 235 | return num_modes; |
226 | } | 236 | } |
227 | 237 | ||
228 | struct drm_encoder *ptn3460_best_encoder(struct drm_connector *connector) | 238 | static struct drm_encoder *ptn3460_best_encoder(struct drm_connector *connector) |
229 | { | 239 | { |
230 | struct ptn3460_bridge *ptn_bridge; | 240 | struct ptn3460_bridge *ptn_bridge = connector_to_ptn3460(connector); |
231 | |||
232 | ptn_bridge = container_of(connector, struct ptn3460_bridge, connector); | ||
233 | 241 | ||
234 | return ptn_bridge->encoder; | 242 | return ptn_bridge->bridge.encoder; |
235 | } | 243 | } |
236 | 244 | ||
237 | struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = { | 245 | static struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = { |
238 | .get_modes = ptn3460_get_modes, | 246 | .get_modes = ptn3460_get_modes, |
239 | .best_encoder = ptn3460_best_encoder, | 247 | .best_encoder = ptn3460_best_encoder, |
240 | }; | 248 | }; |
241 | 249 | ||
242 | enum drm_connector_status ptn3460_detect(struct drm_connector *connector, | 250 | static enum drm_connector_status ptn3460_detect(struct drm_connector *connector, |
243 | bool force) | 251 | bool force) |
244 | { | 252 | { |
245 | return connector_status_connected; | 253 | return connector_status_connected; |
246 | } | 254 | } |
247 | 255 | ||
248 | void ptn3460_connector_destroy(struct drm_connector *connector) | 256 | static void ptn3460_connector_destroy(struct drm_connector *connector) |
249 | { | 257 | { |
250 | drm_connector_cleanup(connector); | 258 | drm_connector_cleanup(connector); |
251 | } | 259 | } |
252 | 260 | ||
253 | struct drm_connector_funcs ptn3460_connector_funcs = { | 261 | static struct drm_connector_funcs ptn3460_connector_funcs = { |
254 | .dpms = drm_helper_connector_dpms, | 262 | .dpms = drm_helper_connector_dpms, |
255 | .fill_modes = drm_helper_probe_single_connector_modes, | 263 | .fill_modes = drm_helper_probe_single_connector_modes, |
256 | .detect = ptn3460_detect, | 264 | .detect = ptn3460_detect, |
257 | .destroy = ptn3460_connector_destroy, | 265 | .destroy = ptn3460_connector_destroy, |
258 | }; | 266 | }; |
259 | 267 | ||
260 | int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder, | 268 | int ptn3460_bridge_attach(struct drm_bridge *bridge) |
261 | struct i2c_client *client, struct device_node *node) | ||
262 | { | 269 | { |
270 | struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge); | ||
263 | int ret; | 271 | int ret; |
264 | struct drm_bridge *bridge; | ||
265 | struct ptn3460_bridge *ptn_bridge; | ||
266 | 272 | ||
267 | bridge = devm_kzalloc(dev->dev, sizeof(*bridge), GFP_KERNEL); | 273 | if (!bridge->encoder) { |
268 | if (!bridge) { | 274 | DRM_ERROR("Parent encoder object not found"); |
269 | DRM_ERROR("Failed to allocate drm bridge\n"); | 275 | return -ENODEV; |
270 | return -ENOMEM; | 276 | } |
277 | |||
278 | ptn_bridge->connector.polled = DRM_CONNECTOR_POLL_HPD; | ||
279 | ret = drm_connector_init(bridge->dev, &ptn_bridge->connector, | ||
280 | &ptn3460_connector_funcs, DRM_MODE_CONNECTOR_LVDS); | ||
281 | if (ret) { | ||
282 | DRM_ERROR("Failed to initialize connector with drm\n"); | ||
283 | return ret; | ||
271 | } | 284 | } |
285 | drm_connector_helper_add(&ptn_bridge->connector, | ||
286 | &ptn3460_connector_helper_funcs); | ||
287 | drm_connector_register(&ptn_bridge->connector); | ||
288 | drm_mode_connector_attach_encoder(&ptn_bridge->connector, | ||
289 | bridge->encoder); | ||
272 | 290 | ||
273 | ptn_bridge = devm_kzalloc(dev->dev, sizeof(*ptn_bridge), GFP_KERNEL); | 291 | if (ptn_bridge->panel) |
292 | drm_panel_attach(ptn_bridge->panel, &ptn_bridge->connector); | ||
293 | |||
294 | drm_helper_hpd_irq_event(ptn_bridge->connector.dev); | ||
295 | |||
296 | return ret; | ||
297 | } | ||
298 | |||
299 | static struct drm_bridge_funcs ptn3460_bridge_funcs = { | ||
300 | .pre_enable = ptn3460_pre_enable, | ||
301 | .enable = ptn3460_enable, | ||
302 | .disable = ptn3460_disable, | ||
303 | .post_disable = ptn3460_post_disable, | ||
304 | .attach = ptn3460_bridge_attach, | ||
305 | }; | ||
306 | |||
307 | static int ptn3460_probe(struct i2c_client *client, | ||
308 | const struct i2c_device_id *id) | ||
309 | { | ||
310 | struct device *dev = &client->dev; | ||
311 | struct ptn3460_bridge *ptn_bridge; | ||
312 | struct device_node *endpoint, *panel_node; | ||
313 | int ret; | ||
314 | |||
315 | ptn_bridge = devm_kzalloc(dev, sizeof(*ptn_bridge), GFP_KERNEL); | ||
274 | if (!ptn_bridge) { | 316 | if (!ptn_bridge) { |
275 | DRM_ERROR("Failed to allocate ptn bridge\n"); | ||
276 | return -ENOMEM; | 317 | return -ENOMEM; |
277 | } | 318 | } |
278 | 319 | ||
279 | ptn_bridge->client = client; | 320 | endpoint = of_graph_get_next_endpoint(dev->of_node, NULL); |
280 | ptn_bridge->encoder = encoder; | 321 | if (endpoint) { |
281 | ptn_bridge->bridge = bridge; | 322 | panel_node = of_graph_get_remote_port_parent(endpoint); |
282 | ptn_bridge->gpio_pd_n = of_get_named_gpio(node, "powerdown-gpio", 0); | 323 | if (panel_node) { |
283 | if (gpio_is_valid(ptn_bridge->gpio_pd_n)) { | 324 | ptn_bridge->panel = of_drm_find_panel(panel_node); |
284 | ret = gpio_request_one(ptn_bridge->gpio_pd_n, | 325 | of_node_put(panel_node); |
285 | GPIOF_OUT_INIT_HIGH, "PTN3460_PD_N"); | 326 | if (!ptn_bridge->panel) |
286 | if (ret) { | 327 | return -EPROBE_DEFER; |
287 | DRM_ERROR("Request powerdown-gpio failed (%d)\n", ret); | ||
288 | return ret; | ||
289 | } | 328 | } |
290 | } | 329 | } |
291 | 330 | ||
292 | ptn_bridge->gpio_rst_n = of_get_named_gpio(node, "reset-gpio", 0); | 331 | ptn_bridge->client = client; |
293 | if (gpio_is_valid(ptn_bridge->gpio_rst_n)) { | 332 | |
294 | /* | 333 | ptn_bridge->gpio_pd_n = devm_gpiod_get(&client->dev, "powerdown"); |
295 | * Request the reset pin low to avoid the bridge being | 334 | if (IS_ERR(ptn_bridge->gpio_pd_n)) { |
296 | * initialized prematurely | 335 | ret = PTR_ERR(ptn_bridge->gpio_pd_n); |
297 | */ | 336 | dev_err(dev, "cannot get gpio_pd_n %d\n", ret); |
298 | ret = gpio_request_one(ptn_bridge->gpio_rst_n, | 337 | return ret; |
299 | GPIOF_OUT_INIT_LOW, "PTN3460_RST_N"); | ||
300 | if (ret) { | ||
301 | DRM_ERROR("Request reset-gpio failed (%d)\n", ret); | ||
302 | gpio_free(ptn_bridge->gpio_pd_n); | ||
303 | return ret; | ||
304 | } | ||
305 | } | 338 | } |
306 | 339 | ||
307 | ret = of_property_read_u32(node, "edid-emulation", | 340 | ret = gpiod_direction_output(ptn_bridge->gpio_pd_n, 1); |
308 | &ptn_bridge->edid_emulation); | ||
309 | if (ret) { | 341 | if (ret) { |
310 | DRM_ERROR("Can't read edid emulation value\n"); | 342 | DRM_ERROR("cannot configure gpio_pd_n\n"); |
311 | goto err; | 343 | return ret; |
312 | } | 344 | } |
313 | 345 | ||
314 | ret = drm_bridge_init(dev, bridge, &ptn3460_bridge_funcs); | 346 | ptn_bridge->gpio_rst_n = devm_gpiod_get(&client->dev, "reset"); |
347 | if (IS_ERR(ptn_bridge->gpio_rst_n)) { | ||
348 | ret = PTR_ERR(ptn_bridge->gpio_rst_n); | ||
349 | DRM_ERROR("cannot get gpio_rst_n %d\n", ret); | ||
350 | return ret; | ||
351 | } | ||
352 | /* | ||
353 | * Request the reset pin low to avoid the bridge being | ||
354 | * initialized prematurely | ||
355 | */ | ||
356 | ret = gpiod_direction_output(ptn_bridge->gpio_rst_n, 0); | ||
315 | if (ret) { | 357 | if (ret) { |
316 | DRM_ERROR("Failed to initialize bridge with drm\n"); | 358 | DRM_ERROR("cannot configure gpio_rst_n\n"); |
317 | goto err; | 359 | return ret; |
318 | } | 360 | } |
319 | 361 | ||
320 | bridge->driver_private = ptn_bridge; | 362 | ret = of_property_read_u32(dev->of_node, "edid-emulation", |
321 | encoder->bridge = bridge; | 363 | &ptn_bridge->edid_emulation); |
364 | if (ret) { | ||
365 | dev_err(dev, "Can't read EDID emulation value\n"); | ||
366 | return ret; | ||
367 | } | ||
322 | 368 | ||
323 | ret = drm_connector_init(dev, &ptn_bridge->connector, | 369 | ptn_bridge->bridge.funcs = &ptn3460_bridge_funcs; |
324 | &ptn3460_connector_funcs, DRM_MODE_CONNECTOR_LVDS); | 370 | ptn_bridge->bridge.of_node = dev->of_node; |
371 | ret = drm_bridge_add(&ptn_bridge->bridge); | ||
325 | if (ret) { | 372 | if (ret) { |
326 | DRM_ERROR("Failed to initialize connector with drm\n"); | 373 | DRM_ERROR("Failed to add bridge\n"); |
327 | goto err; | 374 | return ret; |
328 | } | 375 | } |
329 | drm_connector_helper_add(&ptn_bridge->connector, | 376 | |
330 | &ptn3460_connector_helper_funcs); | 377 | i2c_set_clientdata(client, ptn_bridge); |
331 | drm_connector_register(&ptn_bridge->connector); | ||
332 | drm_mode_connector_attach_encoder(&ptn_bridge->connector, encoder); | ||
333 | 378 | ||
334 | return 0; | 379 | return 0; |
380 | } | ||
335 | 381 | ||
336 | err: | 382 | static int ptn3460_remove(struct i2c_client *client) |
337 | if (gpio_is_valid(ptn_bridge->gpio_pd_n)) | 383 | { |
338 | gpio_free(ptn_bridge->gpio_pd_n); | 384 | struct ptn3460_bridge *ptn_bridge = i2c_get_clientdata(client); |
339 | if (gpio_is_valid(ptn_bridge->gpio_rst_n)) | 385 | |
340 | gpio_free(ptn_bridge->gpio_rst_n); | 386 | drm_bridge_remove(&ptn_bridge->bridge); |
341 | return ret; | 387 | |
388 | return 0; | ||
342 | } | 389 | } |
343 | EXPORT_SYMBOL(ptn3460_init); | 390 | |
391 | static const struct i2c_device_id ptn3460_i2c_table[] = { | ||
392 | {"nxp,ptn3460", 0}, | ||
393 | {}, | ||
394 | }; | ||
395 | MODULE_DEVICE_TABLE(i2c, ptn3460_i2c_table); | ||
396 | |||
397 | static const struct of_device_id ptn3460_match[] = { | ||
398 | { .compatible = "nxp,ptn3460" }, | ||
399 | {}, | ||
400 | }; | ||
401 | MODULE_DEVICE_TABLE(of, ptn3460_match); | ||
402 | |||
403 | static struct i2c_driver ptn3460_driver = { | ||
404 | .id_table = ptn3460_i2c_table, | ||
405 | .probe = ptn3460_probe, | ||
406 | .remove = ptn3460_remove, | ||
407 | .driver = { | ||
408 | .name = "nxp,ptn3460", | ||
409 | .owner = THIS_MODULE, | ||
410 | .of_match_table = ptn3460_match, | ||
411 | }, | ||
412 | }; | ||
413 | module_i2c_driver(ptn3460_driver); | ||
414 | |||
415 | MODULE_AUTHOR("Sean Paul <seanpaul@chromium.org>"); | ||
416 | MODULE_DESCRIPTION("NXP ptn3460 eDP-LVDS converter driver"); | ||
417 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c new file mode 100644 index 000000000000..d1187e571c6d --- /dev/null +++ b/drivers/gpu/drm/drm_bridge.c | |||
@@ -0,0 +1,91 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014 Samsung Electronics Co., Ltd | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sub license, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice (including the | ||
12 | * next paragraph) shall be included in all copies or substantial portions | ||
13 | * of the Software. | ||
14 | * | ||
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL | ||
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
21 | * DEALINGS IN THE SOFTWARE. | ||
22 | */ | ||
23 | |||
24 | #include <linux/err.h> | ||
25 | #include <linux/module.h> | ||
26 | |||
27 | #include <drm/drm_crtc.h> | ||
28 | |||
29 | #include "drm/drmP.h" | ||
30 | |||
31 | static DEFINE_MUTEX(bridge_lock); | ||
32 | static LIST_HEAD(bridge_list); | ||
33 | |||
34 | int drm_bridge_add(struct drm_bridge *bridge) | ||
35 | { | ||
36 | mutex_lock(&bridge_lock); | ||
37 | list_add_tail(&bridge->list, &bridge_list); | ||
38 | mutex_unlock(&bridge_lock); | ||
39 | |||
40 | return 0; | ||
41 | } | ||
42 | EXPORT_SYMBOL(drm_bridge_add); | ||
43 | |||
44 | void drm_bridge_remove(struct drm_bridge *bridge) | ||
45 | { | ||
46 | mutex_lock(&bridge_lock); | ||
47 | list_del_init(&bridge->list); | ||
48 | mutex_unlock(&bridge_lock); | ||
49 | } | ||
50 | EXPORT_SYMBOL(drm_bridge_remove); | ||
51 | |||
52 | extern int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge) | ||
53 | { | ||
54 | if (!dev || !bridge) | ||
55 | return -EINVAL; | ||
56 | |||
57 | if (bridge->dev) | ||
58 | return -EBUSY; | ||
59 | |||
60 | bridge->dev = dev; | ||
61 | |||
62 | if (bridge->funcs->attach) | ||
63 | return bridge->funcs->attach(bridge); | ||
64 | |||
65 | return 0; | ||
66 | } | ||
67 | EXPORT_SYMBOL(drm_bridge_attach); | ||
68 | |||
69 | #ifdef CONFIG_OF | ||
70 | struct drm_bridge *of_drm_find_bridge(struct device_node *np) | ||
71 | { | ||
72 | struct drm_bridge *bridge; | ||
73 | |||
74 | mutex_lock(&bridge_lock); | ||
75 | |||
76 | list_for_each_entry(bridge, &bridge_list, list) { | ||
77 | if (bridge->of_node == np) { | ||
78 | mutex_unlock(&bridge_lock); | ||
79 | return bridge; | ||
80 | } | ||
81 | } | ||
82 | |||
83 | mutex_unlock(&bridge_lock); | ||
84 | return NULL; | ||
85 | } | ||
86 | EXPORT_SYMBOL(of_drm_find_bridge); | ||
87 | #endif | ||
88 | |||
89 | MODULE_AUTHOR("Ajay Kumar <ajaykumar.rs@samsung.com>"); | ||
90 | MODULE_DESCRIPTION("DRM bridge infrastructure"); | ||
91 | MODULE_LICENSE("GPL and additional rights"); | ||
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index b459888f6310..6b00173d1be4 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c | |||
@@ -787,7 +787,7 @@ int drm_display_info_set_bus_formats(struct drm_display_info *info, | |||
787 | if (formats && num_formats) { | 787 | if (formats && num_formats) { |
788 | fmts = kmemdup(formats, sizeof(*formats) * num_formats, | 788 | fmts = kmemdup(formats, sizeof(*formats) * num_formats, |
789 | GFP_KERNEL); | 789 | GFP_KERNEL); |
790 | if (!formats) | 790 | if (!fmts) |
791 | return -ENOMEM; | 791 | return -ENOMEM; |
792 | } | 792 | } |
793 | 793 | ||
@@ -1066,61 +1066,6 @@ void drm_connector_unplug_all(struct drm_device *dev) | |||
1066 | EXPORT_SYMBOL(drm_connector_unplug_all); | 1066 | EXPORT_SYMBOL(drm_connector_unplug_all); |
1067 | 1067 | ||
1068 | /** | 1068 | /** |
1069 | * drm_bridge_init - initialize a drm transcoder/bridge | ||
1070 | * @dev: drm device | ||
1071 | * @bridge: transcoder/bridge to set up | ||
1072 | * @funcs: bridge function table | ||
1073 | * | ||
1074 | * Initialises a preallocated bridge. Bridges should be | ||
1075 | * subclassed as part of driver connector objects. | ||
1076 | * | ||
1077 | * Returns: | ||
1078 | * Zero on success, error code on failure. | ||
1079 | */ | ||
1080 | int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge, | ||
1081 | const struct drm_bridge_funcs *funcs) | ||
1082 | { | ||
1083 | int ret; | ||
1084 | |||
1085 | drm_modeset_lock_all(dev); | ||
1086 | |||
1087 | ret = drm_mode_object_get(dev, &bridge->base, DRM_MODE_OBJECT_BRIDGE); | ||
1088 | if (ret) | ||
1089 | goto out; | ||
1090 | |||
1091 | bridge->dev = dev; | ||
1092 | bridge->funcs = funcs; | ||
1093 | |||
1094 | list_add_tail(&bridge->head, &dev->mode_config.bridge_list); | ||
1095 | dev->mode_config.num_bridge++; | ||
1096 | |||
1097 | out: | ||
1098 | drm_modeset_unlock_all(dev); | ||
1099 | return ret; | ||
1100 | } | ||
1101 | EXPORT_SYMBOL(drm_bridge_init); | ||
1102 | |||
1103 | /** | ||
1104 | * drm_bridge_cleanup - cleans up an initialised bridge | ||
1105 | * @bridge: bridge to cleanup | ||
1106 | * | ||
1107 | * Cleans up the bridge but doesn't free the object. | ||
1108 | */ | ||
1109 | void drm_bridge_cleanup(struct drm_bridge *bridge) | ||
1110 | { | ||
1111 | struct drm_device *dev = bridge->dev; | ||
1112 | |||
1113 | drm_modeset_lock_all(dev); | ||
1114 | drm_mode_object_put(dev, &bridge->base); | ||
1115 | list_del(&bridge->head); | ||
1116 | dev->mode_config.num_bridge--; | ||
1117 | drm_modeset_unlock_all(dev); | ||
1118 | |||
1119 | memset(bridge, 0, sizeof(*bridge)); | ||
1120 | } | ||
1121 | EXPORT_SYMBOL(drm_bridge_cleanup); | ||
1122 | |||
1123 | /** | ||
1124 | * drm_encoder_init - Init a preallocated encoder | 1069 | * drm_encoder_init - Init a preallocated encoder |
1125 | * @dev: drm device | 1070 | * @dev: drm device |
1126 | * @encoder: the encoder to init | 1071 | * @encoder: the encoder to init |
@@ -1715,7 +1660,6 @@ static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *gr | |||
1715 | total_objects += dev->mode_config.num_crtc; | 1660 | total_objects += dev->mode_config.num_crtc; |
1716 | total_objects += dev->mode_config.num_connector; | 1661 | total_objects += dev->mode_config.num_connector; |
1717 | total_objects += dev->mode_config.num_encoder; | 1662 | total_objects += dev->mode_config.num_encoder; |
1718 | total_objects += dev->mode_config.num_bridge; | ||
1719 | 1663 | ||
1720 | group->id_list = kcalloc(total_objects, sizeof(uint32_t), GFP_KERNEL); | 1664 | group->id_list = kcalloc(total_objects, sizeof(uint32_t), GFP_KERNEL); |
1721 | if (!group->id_list) | 1665 | if (!group->id_list) |
@@ -1724,7 +1668,6 @@ static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *gr | |||
1724 | group->num_crtcs = 0; | 1668 | group->num_crtcs = 0; |
1725 | group->num_connectors = 0; | 1669 | group->num_connectors = 0; |
1726 | group->num_encoders = 0; | 1670 | group->num_encoders = 0; |
1727 | group->num_bridges = 0; | ||
1728 | return 0; | 1671 | return 0; |
1729 | } | 1672 | } |
1730 | 1673 | ||
@@ -1744,7 +1687,6 @@ int drm_mode_group_init_legacy_group(struct drm_device *dev, | |||
1744 | struct drm_crtc *crtc; | 1687 | struct drm_crtc *crtc; |
1745 | struct drm_encoder *encoder; | 1688 | struct drm_encoder *encoder; |
1746 | struct drm_connector *connector; | 1689 | struct drm_connector *connector; |
1747 | struct drm_bridge *bridge; | ||
1748 | int ret; | 1690 | int ret; |
1749 | 1691 | ||
1750 | ret = drm_mode_group_init(dev, group); | 1692 | ret = drm_mode_group_init(dev, group); |
@@ -1762,11 +1704,6 @@ int drm_mode_group_init_legacy_group(struct drm_device *dev, | |||
1762 | group->id_list[group->num_crtcs + group->num_encoders + | 1704 | group->id_list[group->num_crtcs + group->num_encoders + |
1763 | group->num_connectors++] = connector->base.id; | 1705 | group->num_connectors++] = connector->base.id; |
1764 | 1706 | ||
1765 | list_for_each_entry(bridge, &dev->mode_config.bridge_list, head) | ||
1766 | group->id_list[group->num_crtcs + group->num_encoders + | ||
1767 | group->num_connectors + group->num_bridges++] = | ||
1768 | bridge->base.id; | ||
1769 | |||
1770 | return 0; | 1707 | return 0; |
1771 | } | 1708 | } |
1772 | EXPORT_SYMBOL(drm_mode_group_init_legacy_group); | 1709 | EXPORT_SYMBOL(drm_mode_group_init_legacy_group); |
@@ -5443,7 +5380,6 @@ void drm_mode_config_init(struct drm_device *dev) | |||
5443 | INIT_LIST_HEAD(&dev->mode_config.fb_list); | 5380 | INIT_LIST_HEAD(&dev->mode_config.fb_list); |
5444 | INIT_LIST_HEAD(&dev->mode_config.crtc_list); | 5381 | INIT_LIST_HEAD(&dev->mode_config.crtc_list); |
5445 | INIT_LIST_HEAD(&dev->mode_config.connector_list); | 5382 | INIT_LIST_HEAD(&dev->mode_config.connector_list); |
5446 | INIT_LIST_HEAD(&dev->mode_config.bridge_list); | ||
5447 | INIT_LIST_HEAD(&dev->mode_config.encoder_list); | 5383 | INIT_LIST_HEAD(&dev->mode_config.encoder_list); |
5448 | INIT_LIST_HEAD(&dev->mode_config.property_list); | 5384 | INIT_LIST_HEAD(&dev->mode_config.property_list); |
5449 | INIT_LIST_HEAD(&dev->mode_config.property_blob_list); | 5385 | INIT_LIST_HEAD(&dev->mode_config.property_blob_list); |
@@ -5483,7 +5419,6 @@ void drm_mode_config_cleanup(struct drm_device *dev) | |||
5483 | struct drm_connector *connector, *ot; | 5419 | struct drm_connector *connector, *ot; |
5484 | struct drm_crtc *crtc, *ct; | 5420 | struct drm_crtc *crtc, *ct; |
5485 | struct drm_encoder *encoder, *enct; | 5421 | struct drm_encoder *encoder, *enct; |
5486 | struct drm_bridge *bridge, *brt; | ||
5487 | struct drm_framebuffer *fb, *fbt; | 5422 | struct drm_framebuffer *fb, *fbt; |
5488 | struct drm_property *property, *pt; | 5423 | struct drm_property *property, *pt; |
5489 | struct drm_property_blob *blob, *bt; | 5424 | struct drm_property_blob *blob, *bt; |
@@ -5494,11 +5429,6 @@ void drm_mode_config_cleanup(struct drm_device *dev) | |||
5494 | encoder->funcs->destroy(encoder); | 5429 | encoder->funcs->destroy(encoder); |
5495 | } | 5430 | } |
5496 | 5431 | ||
5497 | list_for_each_entry_safe(bridge, brt, | ||
5498 | &dev->mode_config.bridge_list, head) { | ||
5499 | bridge->funcs->destroy(bridge); | ||
5500 | } | ||
5501 | |||
5502 | list_for_each_entry_safe(connector, ot, | 5432 | list_for_each_entry_safe(connector, ot, |
5503 | &dev->mode_config.connector_list, head) { | 5433 | &dev->mode_config.connector_list, head) { |
5504 | connector->funcs->destroy(connector); | 5434 | connector->funcs->destroy(connector); |
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index c0644bb865f2..2d5ca8eec13a 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c | |||
@@ -323,8 +323,6 @@ EXPORT_SYMBOL(mipi_dsi_packet_format_is_long); | |||
323 | int mipi_dsi_create_packet(struct mipi_dsi_packet *packet, | 323 | int mipi_dsi_create_packet(struct mipi_dsi_packet *packet, |
324 | const struct mipi_dsi_msg *msg) | 324 | const struct mipi_dsi_msg *msg) |
325 | { | 325 | { |
326 | const u8 *tx = msg->tx_buf; | ||
327 | |||
328 | if (!packet || !msg) | 326 | if (!packet || !msg) |
329 | return -EINVAL; | 327 | return -EINVAL; |
330 | 328 | ||
@@ -353,8 +351,10 @@ int mipi_dsi_create_packet(struct mipi_dsi_packet *packet, | |||
353 | packet->header[2] = (msg->tx_len >> 8) & 0xff; | 351 | packet->header[2] = (msg->tx_len >> 8) & 0xff; |
354 | 352 | ||
355 | packet->payload_length = msg->tx_len; | 353 | packet->payload_length = msg->tx_len; |
356 | packet->payload = tx; | 354 | packet->payload = msg->tx_buf; |
357 | } else { | 355 | } else { |
356 | const u8 *tx = msg->tx_buf; | ||
357 | |||
358 | packet->header[1] = (msg->tx_len > 0) ? tx[0] : 0; | 358 | packet->header[1] = (msg->tx_len > 0) ? tx[0] : 0; |
359 | packet->header[2] = (msg->tx_len > 1) ? tx[1] : 0; | 359 | packet->header[2] = (msg->tx_len > 1) ? tx[1] : 0; |
360 | } | 360 | } |
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c index 34d46aa75416..46f149737bc8 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.c +++ b/drivers/gpu/drm/exynos/exynos_dp_core.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/interrupt.h> | 18 | #include <linux/interrupt.h> |
19 | #include <linux/of.h> | 19 | #include <linux/of.h> |
20 | #include <linux/of_gpio.h> | 20 | #include <linux/of_gpio.h> |
21 | #include <linux/of_graph.h> | ||
21 | #include <linux/gpio.h> | 22 | #include <linux/gpio.h> |
22 | #include <linux/component.h> | 23 | #include <linux/component.h> |
23 | #include <linux/phy/phy.h> | 24 | #include <linux/phy/phy.h> |
@@ -993,32 +994,20 @@ static struct drm_connector_helper_funcs exynos_dp_connector_helper_funcs = { | |||
993 | .best_encoder = exynos_dp_best_encoder, | 994 | .best_encoder = exynos_dp_best_encoder, |
994 | }; | 995 | }; |
995 | 996 | ||
996 | static bool find_bridge(const char *compat, struct bridge_init *bridge) | ||
997 | { | ||
998 | bridge->client = NULL; | ||
999 | bridge->node = of_find_compatible_node(NULL, NULL, compat); | ||
1000 | if (!bridge->node) | ||
1001 | return false; | ||
1002 | |||
1003 | bridge->client = of_find_i2c_device_by_node(bridge->node); | ||
1004 | if (!bridge->client) | ||
1005 | return false; | ||
1006 | |||
1007 | return true; | ||
1008 | } | ||
1009 | |||
1010 | /* returns the number of bridges attached */ | 997 | /* returns the number of bridges attached */ |
1011 | static int exynos_drm_attach_lcd_bridge(struct drm_device *dev, | 998 | static int exynos_drm_attach_lcd_bridge(struct exynos_dp_device *dp, |
1012 | struct drm_encoder *encoder) | 999 | struct drm_encoder *encoder) |
1013 | { | 1000 | { |
1014 | struct bridge_init bridge; | ||
1015 | int ret; | 1001 | int ret; |
1016 | 1002 | ||
1017 | if (find_bridge("nxp,ptn3460", &bridge)) { | 1003 | encoder->bridge = dp->bridge; |
1018 | ret = ptn3460_init(dev, encoder, bridge.client, bridge.node); | 1004 | dp->bridge->encoder = encoder; |
1019 | if (!ret) | 1005 | ret = drm_bridge_attach(encoder->dev, dp->bridge); |
1020 | return 1; | 1006 | if (ret) { |
1007 | DRM_ERROR("Failed to attach bridge to drm\n"); | ||
1008 | return ret; | ||
1021 | } | 1009 | } |
1010 | |||
1022 | return 0; | 1011 | return 0; |
1023 | } | 1012 | } |
1024 | 1013 | ||
@@ -1032,9 +1021,11 @@ static int exynos_dp_create_connector(struct exynos_drm_display *display, | |||
1032 | dp->encoder = encoder; | 1021 | dp->encoder = encoder; |
1033 | 1022 | ||
1034 | /* Pre-empt DP connector creation if there's a bridge */ | 1023 | /* Pre-empt DP connector creation if there's a bridge */ |
1035 | ret = exynos_drm_attach_lcd_bridge(dp->drm_dev, encoder); | 1024 | if (dp->bridge) { |
1036 | if (ret) | 1025 | ret = exynos_drm_attach_lcd_bridge(dp, encoder); |
1037 | return 0; | 1026 | if (!ret) |
1027 | return 0; | ||
1028 | } | ||
1038 | 1029 | ||
1039 | connector->polled = DRM_CONNECTOR_POLL_HPD; | 1030 | connector->polled = DRM_CONNECTOR_POLL_HPD; |
1040 | 1031 | ||
@@ -1241,7 +1232,7 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data) | |||
1241 | } | 1232 | } |
1242 | } | 1233 | } |
1243 | 1234 | ||
1244 | if (!dp->panel) { | 1235 | if (!dp->panel && !dp->bridge) { |
1245 | ret = exynos_dp_dt_parse_panel(dp); | 1236 | ret = exynos_dp_dt_parse_panel(dp); |
1246 | if (ret) | 1237 | if (ret) |
1247 | return ret; | 1238 | return ret; |
@@ -1325,7 +1316,7 @@ static const struct component_ops exynos_dp_ops = { | |||
1325 | static int exynos_dp_probe(struct platform_device *pdev) | 1316 | static int exynos_dp_probe(struct platform_device *pdev) |
1326 | { | 1317 | { |
1327 | struct device *dev = &pdev->dev; | 1318 | struct device *dev = &pdev->dev; |
1328 | struct device_node *panel_node; | 1319 | struct device_node *panel_node, *bridge_node, *endpoint; |
1329 | struct exynos_dp_device *dp; | 1320 | struct exynos_dp_device *dp; |
1330 | int ret; | 1321 | int ret; |
1331 | 1322 | ||
@@ -1351,6 +1342,18 @@ static int exynos_dp_probe(struct platform_device *pdev) | |||
1351 | return -EPROBE_DEFER; | 1342 | return -EPROBE_DEFER; |
1352 | } | 1343 | } |
1353 | 1344 | ||
1345 | endpoint = of_graph_get_next_endpoint(dev->of_node, NULL); | ||
1346 | if (endpoint) { | ||
1347 | bridge_node = of_graph_get_remote_port_parent(endpoint); | ||
1348 | if (bridge_node) { | ||
1349 | dp->bridge = of_drm_find_bridge(bridge_node); | ||
1350 | of_node_put(bridge_node); | ||
1351 | if (!dp->bridge) | ||
1352 | return -EPROBE_DEFER; | ||
1353 | } else | ||
1354 | return -EPROBE_DEFER; | ||
1355 | } | ||
1356 | |||
1354 | ret = component_add(&pdev->dev, &exynos_dp_ops); | 1357 | ret = component_add(&pdev->dev, &exynos_dp_ops); |
1355 | if (ret) | 1358 | if (ret) |
1356 | exynos_drm_component_del(&pdev->dev, | 1359 | exynos_drm_component_del(&pdev->dev, |
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.h b/drivers/gpu/drm/exynos/exynos_dp_core.h index 164f171168e7..a4e799679669 100644 --- a/drivers/gpu/drm/exynos/exynos_dp_core.h +++ b/drivers/gpu/drm/exynos/exynos_dp_core.h | |||
@@ -153,6 +153,7 @@ struct exynos_dp_device { | |||
153 | struct drm_connector connector; | 153 | struct drm_connector connector; |
154 | struct drm_encoder *encoder; | 154 | struct drm_encoder *encoder; |
155 | struct drm_panel *panel; | 155 | struct drm_panel *panel; |
156 | struct drm_bridge *bridge; | ||
156 | struct clk *clock; | 157 | struct clk *clock; |
157 | unsigned int irq; | 158 | unsigned int irq; |
158 | void __iomem *reg_base; | 159 | void __iomem *reg_base; |
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c index 062c68725376..95f7b8d0f3ef 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c | |||
@@ -247,9 +247,9 @@ int hdmi_modeset_init(struct hdmi *hdmi, | |||
247 | return 0; | 247 | return 0; |
248 | 248 | ||
249 | fail: | 249 | fail: |
250 | /* bridge/connector are normally destroyed by drm: */ | 250 | /* bridge is normally destroyed by drm: */ |
251 | if (hdmi->bridge) { | 251 | if (hdmi->bridge) { |
252 | hdmi->bridge->funcs->destroy(hdmi->bridge); | 252 | hdmi_bridge_destroy(hdmi->bridge); |
253 | hdmi->bridge = NULL; | 253 | hdmi->bridge = NULL; |
254 | } | 254 | } |
255 | if (hdmi->connector) { | 255 | if (hdmi->connector) { |
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h index 43e654f751b7..4d4cad42a776 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.h +++ b/drivers/gpu/drm/msm/hdmi/hdmi.h | |||
@@ -146,6 +146,7 @@ void hdmi_audio_set_sample_rate(struct hdmi *hdmi, int rate); | |||
146 | */ | 146 | */ |
147 | 147 | ||
148 | struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi); | 148 | struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi); |
149 | void hdmi_bridge_destroy(struct drm_bridge *bridge); | ||
149 | 150 | ||
150 | /* | 151 | /* |
151 | * hdmi connector: | 152 | * hdmi connector: |
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c index 6902ad6da710..d6f8d5818e18 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | |||
@@ -23,10 +23,9 @@ struct hdmi_bridge { | |||
23 | }; | 23 | }; |
24 | #define to_hdmi_bridge(x) container_of(x, struct hdmi_bridge, base) | 24 | #define to_hdmi_bridge(x) container_of(x, struct hdmi_bridge, base) |
25 | 25 | ||
26 | static void hdmi_bridge_destroy(struct drm_bridge *bridge) | 26 | void hdmi_bridge_destroy(struct drm_bridge *bridge) |
27 | { | 27 | { |
28 | struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); | 28 | struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); |
29 | drm_bridge_cleanup(bridge); | ||
30 | kfree(hdmi_bridge); | 29 | kfree(hdmi_bridge); |
31 | } | 30 | } |
32 | 31 | ||
@@ -200,7 +199,6 @@ static const struct drm_bridge_funcs hdmi_bridge_funcs = { | |||
200 | .disable = hdmi_bridge_disable, | 199 | .disable = hdmi_bridge_disable, |
201 | .post_disable = hdmi_bridge_post_disable, | 200 | .post_disable = hdmi_bridge_post_disable, |
202 | .mode_set = hdmi_bridge_mode_set, | 201 | .mode_set = hdmi_bridge_mode_set, |
203 | .destroy = hdmi_bridge_destroy, | ||
204 | }; | 202 | }; |
205 | 203 | ||
206 | 204 | ||
@@ -220,8 +218,9 @@ struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi) | |||
220 | hdmi_bridge->hdmi = hdmi; | 218 | hdmi_bridge->hdmi = hdmi; |
221 | 219 | ||
222 | bridge = &hdmi_bridge->base; | 220 | bridge = &hdmi_bridge->base; |
221 | bridge->funcs = &hdmi_bridge_funcs; | ||
223 | 222 | ||
224 | drm_bridge_init(hdmi->dev, bridge, &hdmi_bridge_funcs); | 223 | drm_bridge_attach(hdmi->dev, bridge); |
225 | 224 | ||
226 | return bridge; | 225 | return bridge; |
227 | 226 | ||
diff --git a/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c b/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c index 9d81759d82fc..3cce3ca19601 100644 --- a/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c +++ b/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c | |||
@@ -19,8 +19,6 @@ | |||
19 | 19 | ||
20 | #include <video/mipi_display.h> | 20 | #include <video/mipi_display.h> |
21 | 21 | ||
22 | #include <linux/host1x.h> | ||
23 | |||
24 | struct sharp_panel { | 22 | struct sharp_panel { |
25 | struct drm_panel base; | 23 | struct drm_panel base; |
26 | /* the datasheet refers to them as DSI-LINK1 and DSI-LINK2 */ | 24 | /* 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) | |||
41 | return container_of(panel, struct sharp_panel, base); | 39 | return container_of(panel, struct sharp_panel, base); |
42 | } | 40 | } |
43 | 41 | ||
42 | static void sharp_wait_frames(struct sharp_panel *sharp, unsigned int frames) | ||
43 | { | ||
44 | unsigned int refresh = drm_mode_vrefresh(sharp->mode); | ||
45 | |||
46 | if (WARN_ON(frames > refresh)) | ||
47 | return; | ||
48 | |||
49 | msleep(1000 / (refresh / frames)); | ||
50 | } | ||
51 | |||
44 | static int sharp_panel_write(struct sharp_panel *sharp, u16 offset, u8 value) | 52 | static int sharp_panel_write(struct sharp_panel *sharp, u16 offset, u8 value) |
45 | { | 53 | { |
46 | u8 payload[3] = { offset >> 8, offset & 0xff, value }; | 54 | u8 payload[3] = { offset >> 8, offset & 0xff, value }; |
@@ -106,6 +114,8 @@ static int sharp_panel_unprepare(struct drm_panel *panel) | |||
106 | if (!sharp->prepared) | 114 | if (!sharp->prepared) |
107 | return 0; | 115 | return 0; |
108 | 116 | ||
117 | sharp_wait_frames(sharp, 4); | ||
118 | |||
109 | err = mipi_dsi_dcs_set_display_off(sharp->link1); | 119 | err = mipi_dsi_dcs_set_display_off(sharp->link1); |
110 | if (err < 0) | 120 | if (err < 0) |
111 | dev_err(panel->dev, "failed to set display off: %d\n", err); | 121 | 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) | |||
170 | if (err < 0) | 180 | if (err < 0) |
171 | return err; | 181 | return err; |
172 | 182 | ||
173 | usleep_range(10000, 20000); | 183 | /* |
174 | 184 | * According to the datasheet, the panel needs around 10 ms to fully | |
175 | err = mipi_dsi_dcs_soft_reset(sharp->link1); | 185 | * power up. At least another 120 ms is required before exiting sleep |
176 | if (err < 0) { | 186 | * mode to make sure the panel is ready. Throw in another 20 ms for |
177 | dev_err(panel->dev, "soft reset failed: %d\n", err); | 187 | * good measure. |
178 | goto poweroff; | 188 | */ |
179 | } | 189 | msleep(150); |
180 | |||
181 | msleep(120); | ||
182 | 190 | ||
183 | err = mipi_dsi_dcs_exit_sleep_mode(sharp->link1); | 191 | err = mipi_dsi_dcs_exit_sleep_mode(sharp->link1); |
184 | if (err < 0) { | 192 | if (err < 0) { |
@@ -238,6 +246,9 @@ static int sharp_panel_prepare(struct drm_panel *panel) | |||
238 | 246 | ||
239 | sharp->prepared = true; | 247 | sharp->prepared = true; |
240 | 248 | ||
249 | /* wait for 6 frames before continuing */ | ||
250 | sharp_wait_frames(sharp, 6); | ||
251 | |||
241 | return 0; | 252 | return 0; |
242 | 253 | ||
243 | poweroff: | 254 | poweroff: |
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 6049d245c20e..39806c335339 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c | |||
@@ -448,6 +448,34 @@ static const struct panel_desc auo_b133htn01 = { | |||
448 | }, | 448 | }, |
449 | }; | 449 | }; |
450 | 450 | ||
451 | static const struct drm_display_mode avic_tm070ddh03_mode = { | ||
452 | .clock = 51200, | ||
453 | .hdisplay = 1024, | ||
454 | .hsync_start = 1024 + 160, | ||
455 | .hsync_end = 1024 + 160 + 4, | ||
456 | .htotal = 1024 + 160 + 4 + 156, | ||
457 | .vdisplay = 600, | ||
458 | .vsync_start = 600 + 17, | ||
459 | .vsync_end = 600 + 17 + 1, | ||
460 | .vtotal = 600 + 17 + 1 + 17, | ||
461 | .vrefresh = 60, | ||
462 | }; | ||
463 | |||
464 | static const struct panel_desc avic_tm070ddh03 = { | ||
465 | .modes = &avic_tm070ddh03_mode, | ||
466 | .num_modes = 1, | ||
467 | .bpc = 8, | ||
468 | .size = { | ||
469 | .width = 154, | ||
470 | .height = 90, | ||
471 | }, | ||
472 | .delay = { | ||
473 | .prepare = 20, | ||
474 | .enable = 200, | ||
475 | .disable = 200, | ||
476 | }, | ||
477 | }; | ||
478 | |||
451 | static const struct drm_display_mode chunghwa_claa101wa01a_mode = { | 479 | static const struct drm_display_mode chunghwa_claa101wa01a_mode = { |
452 | .clock = 72070, | 480 | .clock = 72070, |
453 | .hdisplay = 1366, | 481 | .hdisplay = 1366, |
@@ -566,6 +594,29 @@ static const struct panel_desc foxlink_fl500wvr00_a0t = { | |||
566 | .bus_format = MEDIA_BUS_FMT_RGB888_1X24, | 594 | .bus_format = MEDIA_BUS_FMT_RGB888_1X24, |
567 | }; | 595 | }; |
568 | 596 | ||
597 | static const struct drm_display_mode giantplus_gpg482739qs5_mode = { | ||
598 | .clock = 9000, | ||
599 | .hdisplay = 480, | ||
600 | .hsync_start = 480 + 5, | ||
601 | .hsync_end = 480 + 5 + 1, | ||
602 | .htotal = 480 + 5 + 1 + 40, | ||
603 | .vdisplay = 272, | ||
604 | .vsync_start = 272 + 8, | ||
605 | .vsync_end = 272 + 8 + 1, | ||
606 | .vtotal = 272 + 8 + 1 + 8, | ||
607 | .vrefresh = 60, | ||
608 | }; | ||
609 | |||
610 | static const struct panel_desc giantplus_gpg482739qs5 = { | ||
611 | .modes = &giantplus_gpg482739qs5_mode, | ||
612 | .num_modes = 1, | ||
613 | .bpc = 8, | ||
614 | .size = { | ||
615 | .width = 95, | ||
616 | .height = 54, | ||
617 | }, | ||
618 | }; | ||
619 | |||
569 | static const struct drm_display_mode hannstar_hsd070pww1_mode = { | 620 | static const struct drm_display_mode hannstar_hsd070pww1_mode = { |
570 | .clock = 71100, | 621 | .clock = 71100, |
571 | .hdisplay = 1280, | 622 | .hdisplay = 1280, |
@@ -745,6 +796,9 @@ static const struct of_device_id platform_of_match[] = { | |||
745 | .compatible = "auo,b133xtn01", | 796 | .compatible = "auo,b133xtn01", |
746 | .data = &auo_b133xtn01, | 797 | .data = &auo_b133xtn01, |
747 | }, { | 798 | }, { |
799 | .compatible = "avic,tm070ddh03", | ||
800 | .data = &avic_tm070ddh03, | ||
801 | }, { | ||
748 | .compatible = "chunghwa,claa101wa01a", | 802 | .compatible = "chunghwa,claa101wa01a", |
749 | .data = &chunghwa_claa101wa01a | 803 | .data = &chunghwa_claa101wa01a |
750 | }, { | 804 | }, { |
@@ -763,6 +817,9 @@ static const struct of_device_id platform_of_match[] = { | |||
763 | .compatible = "foxlink,fl500wvr00-a0t", | 817 | .compatible = "foxlink,fl500wvr00-a0t", |
764 | .data = &foxlink_fl500wvr00_a0t, | 818 | .data = &foxlink_fl500wvr00_a0t, |
765 | }, { | 819 | }, { |
820 | .compatible = "giantplus,gpg482739qs5", | ||
821 | .data = &giantplus_gpg482739qs5 | ||
822 | }, { | ||
766 | .compatible = "hannstar,hsd070pww1", | 823 | .compatible = "hannstar,hsd070pww1", |
767 | .data = &hannstar_hsd070pww1, | 824 | .data = &hannstar_hsd070pww1, |
768 | }, { | 825 | }, { |
diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c index 651afad21f92..aeb5070c8363 100644 --- a/drivers/gpu/drm/sti/sti_dvo.c +++ b/drivers/gpu/drm/sti/sti_dvo.c | |||
@@ -91,6 +91,7 @@ struct sti_dvo { | |||
91 | struct dvo_config *config; | 91 | struct dvo_config *config; |
92 | bool enabled; | 92 | bool enabled; |
93 | struct drm_encoder *encoder; | 93 | struct drm_encoder *encoder; |
94 | struct drm_bridge *bridge; | ||
94 | }; | 95 | }; |
95 | 96 | ||
96 | struct sti_dvo_connector { | 97 | struct sti_dvo_connector { |
@@ -272,19 +273,12 @@ static void sti_dvo_bridge_nope(struct drm_bridge *bridge) | |||
272 | /* do nothing */ | 273 | /* do nothing */ |
273 | } | 274 | } |
274 | 275 | ||
275 | static void sti_dvo_brigde_destroy(struct drm_bridge *bridge) | ||
276 | { | ||
277 | drm_bridge_cleanup(bridge); | ||
278 | kfree(bridge); | ||
279 | } | ||
280 | |||
281 | static const struct drm_bridge_funcs sti_dvo_bridge_funcs = { | 276 | static const struct drm_bridge_funcs sti_dvo_bridge_funcs = { |
282 | .pre_enable = sti_dvo_pre_enable, | 277 | .pre_enable = sti_dvo_pre_enable, |
283 | .enable = sti_dvo_bridge_nope, | 278 | .enable = sti_dvo_bridge_nope, |
284 | .disable = sti_dvo_disable, | 279 | .disable = sti_dvo_disable, |
285 | .post_disable = sti_dvo_bridge_nope, | 280 | .post_disable = sti_dvo_bridge_nope, |
286 | .mode_set = sti_dvo_set_mode, | 281 | .mode_set = sti_dvo_set_mode, |
287 | .destroy = sti_dvo_brigde_destroy, | ||
288 | }; | 282 | }; |
289 | 283 | ||
290 | static int sti_dvo_connector_get_modes(struct drm_connector *connector) | 284 | 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) | |||
416 | return -ENOMEM; | 410 | return -ENOMEM; |
417 | 411 | ||
418 | bridge->driver_private = dvo; | 412 | bridge->driver_private = dvo; |
419 | drm_bridge_init(drm_dev, bridge, &sti_dvo_bridge_funcs); | 413 | bridge->funcs = &sti_dvo_bridge_funcs; |
414 | bridge->of_node = dvo->dev.of_node; | ||
415 | err = drm_bridge_add(bridge); | ||
416 | if (err) { | ||
417 | DRM_ERROR("Failed to add bridge\n"); | ||
418 | return err; | ||
419 | } | ||
420 | 420 | ||
421 | err = drm_bridge_attach(drm_dev, bridge); | ||
422 | if (err) { | ||
423 | DRM_ERROR("Failed to attach bridge\n"); | ||
424 | return err; | ||
425 | } | ||
426 | |||
427 | dvo->bridge = bridge; | ||
421 | encoder->bridge = bridge; | 428 | encoder->bridge = bridge; |
422 | connector->encoder = encoder; | 429 | connector->encoder = encoder; |
423 | dvo->encoder = encoder; | 430 | dvo->encoder = encoder; |
@@ -446,7 +453,7 @@ static int sti_dvo_bind(struct device *dev, struct device *master, void *data) | |||
446 | err_sysfs: | 453 | err_sysfs: |
447 | drm_connector_unregister(drm_connector); | 454 | drm_connector_unregister(drm_connector); |
448 | err_connector: | 455 | err_connector: |
449 | drm_bridge_cleanup(bridge); | 456 | drm_bridge_remove(bridge); |
450 | drm_connector_cleanup(drm_connector); | 457 | drm_connector_cleanup(drm_connector); |
451 | return -EINVAL; | 458 | return -EINVAL; |
452 | } | 459 | } |
@@ -454,7 +461,9 @@ err_connector: | |||
454 | static void sti_dvo_unbind(struct device *dev, | 461 | static void sti_dvo_unbind(struct device *dev, |
455 | struct device *master, void *data) | 462 | struct device *master, void *data) |
456 | { | 463 | { |
457 | /* do nothing */ | 464 | struct sti_dvo *dvo = dev_get_drvdata(dev); |
465 | |||
466 | drm_bridge_remove(dvo->bridge); | ||
458 | } | 467 | } |
459 | 468 | ||
460 | static const struct component_ops sti_dvo_ops = { | 469 | static const struct component_ops sti_dvo_ops = { |
diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c index 2ae9a9b73666..a9bbb081ecad 100644 --- a/drivers/gpu/drm/sti/sti_hda.c +++ b/drivers/gpu/drm/sti/sti_hda.c | |||
@@ -508,19 +508,12 @@ static void sti_hda_bridge_nope(struct drm_bridge *bridge) | |||
508 | /* do nothing */ | 508 | /* do nothing */ |
509 | } | 509 | } |
510 | 510 | ||
511 | static void sti_hda_brigde_destroy(struct drm_bridge *bridge) | ||
512 | { | ||
513 | drm_bridge_cleanup(bridge); | ||
514 | kfree(bridge); | ||
515 | } | ||
516 | |||
517 | static const struct drm_bridge_funcs sti_hda_bridge_funcs = { | 511 | static const struct drm_bridge_funcs sti_hda_bridge_funcs = { |
518 | .pre_enable = sti_hda_pre_enable, | 512 | .pre_enable = sti_hda_pre_enable, |
519 | .enable = sti_hda_bridge_nope, | 513 | .enable = sti_hda_bridge_nope, |
520 | .disable = sti_hda_disable, | 514 | .disable = sti_hda_disable, |
521 | .post_disable = sti_hda_bridge_nope, | 515 | .post_disable = sti_hda_bridge_nope, |
522 | .mode_set = sti_hda_set_mode, | 516 | .mode_set = sti_hda_set_mode, |
523 | .destroy = sti_hda_brigde_destroy, | ||
524 | }; | 517 | }; |
525 | 518 | ||
526 | static int sti_hda_connector_get_modes(struct drm_connector *connector) | 519 | 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) | |||
664 | return -ENOMEM; | 657 | return -ENOMEM; |
665 | 658 | ||
666 | bridge->driver_private = hda; | 659 | bridge->driver_private = hda; |
667 | drm_bridge_init(drm_dev, bridge, &sti_hda_bridge_funcs); | 660 | bridge->funcs = &sti_hda_bridge_funcs; |
661 | drm_bridge_attach(drm_dev, bridge); | ||
668 | 662 | ||
669 | encoder->bridge = bridge; | 663 | encoder->bridge = bridge; |
670 | connector->encoder = encoder; | 664 | connector->encoder = encoder; |
@@ -693,7 +687,6 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data) | |||
693 | err_sysfs: | 687 | err_sysfs: |
694 | drm_connector_unregister(drm_connector); | 688 | drm_connector_unregister(drm_connector); |
695 | err_connector: | 689 | err_connector: |
696 | drm_bridge_cleanup(bridge); | ||
697 | drm_connector_cleanup(drm_connector); | 690 | drm_connector_cleanup(drm_connector); |
698 | return -EINVAL; | 691 | return -EINVAL; |
699 | } | 692 | } |
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index d032e024b0b8..e840ca5de401 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c | |||
@@ -463,19 +463,12 @@ static void sti_hdmi_bridge_nope(struct drm_bridge *bridge) | |||
463 | /* do nothing */ | 463 | /* do nothing */ |
464 | } | 464 | } |
465 | 465 | ||
466 | static void sti_hdmi_brigde_destroy(struct drm_bridge *bridge) | ||
467 | { | ||
468 | drm_bridge_cleanup(bridge); | ||
469 | kfree(bridge); | ||
470 | } | ||
471 | |||
472 | static const struct drm_bridge_funcs sti_hdmi_bridge_funcs = { | 466 | static const struct drm_bridge_funcs sti_hdmi_bridge_funcs = { |
473 | .pre_enable = sti_hdmi_pre_enable, | 467 | .pre_enable = sti_hdmi_pre_enable, |
474 | .enable = sti_hdmi_bridge_nope, | 468 | .enable = sti_hdmi_bridge_nope, |
475 | .disable = sti_hdmi_disable, | 469 | .disable = sti_hdmi_disable, |
476 | .post_disable = sti_hdmi_bridge_nope, | 470 | .post_disable = sti_hdmi_bridge_nope, |
477 | .mode_set = sti_hdmi_set_mode, | 471 | .mode_set = sti_hdmi_set_mode, |
478 | .destroy = sti_hdmi_brigde_destroy, | ||
479 | }; | 472 | }; |
480 | 473 | ||
481 | static int sti_hdmi_connector_get_modes(struct drm_connector *connector) | 474 | 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) | |||
635 | goto err_adapt; | 628 | goto err_adapt; |
636 | 629 | ||
637 | bridge->driver_private = hdmi; | 630 | bridge->driver_private = hdmi; |
638 | drm_bridge_init(drm_dev, bridge, &sti_hdmi_bridge_funcs); | 631 | bridge->funcs = &sti_hdmi_bridge_funcs; |
632 | drm_bridge_attach(drm_dev, bridge); | ||
639 | 633 | ||
640 | encoder->bridge = bridge; | 634 | encoder->bridge = bridge; |
641 | connector->encoder = encoder; | 635 | connector->encoder = encoder; |
@@ -667,7 +661,6 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data) | |||
667 | err_sysfs: | 661 | err_sysfs: |
668 | drm_connector_unregister(drm_connector); | 662 | drm_connector_unregister(drm_connector); |
669 | err_connector: | 663 | err_connector: |
670 | drm_bridge_cleanup(bridge); | ||
671 | drm_connector_cleanup(drm_connector); | 664 | drm_connector_cleanup(drm_connector); |
672 | err_adapt: | 665 | err_adapt: |
673 | put_device(&hdmi->ddc_adapt->dev); | 666 | put_device(&hdmi->ddc_adapt->dev); |
diff --git a/include/drm/bridge/ptn3460.h b/include/drm/bridge/ptn3460.h index ff62344fec6c..b11f8e17e72f 100644 --- a/include/drm/bridge/ptn3460.h +++ b/include/drm/bridge/ptn3460.h | |||
@@ -15,6 +15,7 @@ | |||
15 | #define _DRM_BRIDGE_PTN3460_H_ | 15 | #define _DRM_BRIDGE_PTN3460_H_ |
16 | 16 | ||
17 | struct drm_device; | 17 | struct drm_device; |
18 | struct drm_bridge; | ||
18 | struct drm_encoder; | 19 | struct drm_encoder; |
19 | struct i2c_client; | 20 | struct i2c_client; |
20 | struct device_node; | 21 | struct device_node; |
@@ -23,6 +24,9 @@ struct device_node; | |||
23 | 24 | ||
24 | int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder, | 25 | int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder, |
25 | struct i2c_client *client, struct device_node *node); | 26 | struct i2c_client *client, struct device_node *node); |
27 | |||
28 | void ptn3460_destroy(struct drm_bridge *bridge); | ||
29 | |||
26 | #else | 30 | #else |
27 | 31 | ||
28 | static inline int ptn3460_init(struct drm_device *dev, | 32 | static inline int ptn3460_init(struct drm_device *dev, |
@@ -32,6 +36,10 @@ static inline int ptn3460_init(struct drm_device *dev, | |||
32 | return 0; | 36 | return 0; |
33 | } | 37 | } |
34 | 38 | ||
39 | static inline void ptn3460_destroy(struct drm_bridge *bridge) | ||
40 | { | ||
41 | } | ||
42 | |||
35 | #endif | 43 | #endif |
36 | 44 | ||
37 | #endif | 45 | #endif |
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 02614170c034..920e21a8f3fd 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h | |||
@@ -868,15 +868,16 @@ struct drm_plane { | |||
868 | 868 | ||
869 | /** | 869 | /** |
870 | * struct drm_bridge_funcs - drm_bridge control functions | 870 | * struct drm_bridge_funcs - drm_bridge control functions |
871 | * @attach: Called during drm_bridge_attach | ||
871 | * @mode_fixup: Try to fixup (or reject entirely) proposed mode for this bridge | 872 | * @mode_fixup: Try to fixup (or reject entirely) proposed mode for this bridge |
872 | * @disable: Called right before encoder prepare, disables the bridge | 873 | * @disable: Called right before encoder prepare, disables the bridge |
873 | * @post_disable: Called right after encoder prepare, for lockstepped disable | 874 | * @post_disable: Called right after encoder prepare, for lockstepped disable |
874 | * @mode_set: Set this mode to the bridge | 875 | * @mode_set: Set this mode to the bridge |
875 | * @pre_enable: Called right before encoder commit, for lockstepped commit | 876 | * @pre_enable: Called right before encoder commit, for lockstepped commit |
876 | * @enable: Called right after encoder commit, enables the bridge | 877 | * @enable: Called right after encoder commit, enables the bridge |
877 | * @destroy: make object go away | ||
878 | */ | 878 | */ |
879 | struct drm_bridge_funcs { | 879 | struct drm_bridge_funcs { |
880 | int (*attach)(struct drm_bridge *bridge); | ||
880 | bool (*mode_fixup)(struct drm_bridge *bridge, | 881 | bool (*mode_fixup)(struct drm_bridge *bridge, |
881 | const struct drm_display_mode *mode, | 882 | const struct drm_display_mode *mode, |
882 | struct drm_display_mode *adjusted_mode); | 883 | struct drm_display_mode *adjusted_mode); |
@@ -887,22 +888,24 @@ struct drm_bridge_funcs { | |||
887 | struct drm_display_mode *adjusted_mode); | 888 | struct drm_display_mode *adjusted_mode); |
888 | void (*pre_enable)(struct drm_bridge *bridge); | 889 | void (*pre_enable)(struct drm_bridge *bridge); |
889 | void (*enable)(struct drm_bridge *bridge); | 890 | void (*enable)(struct drm_bridge *bridge); |
890 | void (*destroy)(struct drm_bridge *bridge); | ||
891 | }; | 891 | }; |
892 | 892 | ||
893 | /** | 893 | /** |
894 | * struct drm_bridge - central DRM bridge control structure | 894 | * struct drm_bridge - central DRM bridge control structure |
895 | * @dev: DRM device this bridge belongs to | 895 | * @dev: DRM device this bridge belongs to |
896 | * @head: list management | 896 | * @of_node: device node pointer to the bridge |
897 | * @list: to keep track of all added bridges | ||
897 | * @base: base mode object | 898 | * @base: base mode object |
898 | * @funcs: control functions | 899 | * @funcs: control functions |
899 | * @driver_private: pointer to the bridge driver's internal context | 900 | * @driver_private: pointer to the bridge driver's internal context |
900 | */ | 901 | */ |
901 | struct drm_bridge { | 902 | struct drm_bridge { |
902 | struct drm_device *dev; | 903 | struct drm_device *dev; |
903 | struct list_head head; | 904 | struct drm_encoder *encoder; |
904 | 905 | #ifdef CONFIG_OF | |
905 | struct drm_mode_object base; | 906 | struct device_node *of_node; |
907 | #endif | ||
908 | struct list_head list; | ||
906 | 909 | ||
907 | const struct drm_bridge_funcs *funcs; | 910 | const struct drm_bridge_funcs *funcs; |
908 | void *driver_private; | 911 | void *driver_private; |
@@ -1007,7 +1010,6 @@ struct drm_mode_group { | |||
1007 | uint32_t num_crtcs; | 1010 | uint32_t num_crtcs; |
1008 | uint32_t num_encoders; | 1011 | uint32_t num_encoders; |
1009 | uint32_t num_connectors; | 1012 | uint32_t num_connectors; |
1010 | uint32_t num_bridges; | ||
1011 | 1013 | ||
1012 | /* list of object IDs for this group */ | 1014 | /* list of object IDs for this group */ |
1013 | uint32_t *id_list; | 1015 | uint32_t *id_list; |
@@ -1026,8 +1028,6 @@ struct drm_mode_group { | |||
1026 | * @fb_list: list of framebuffers available | 1028 | * @fb_list: list of framebuffers available |
1027 | * @num_connector: number of connectors on this device | 1029 | * @num_connector: number of connectors on this device |
1028 | * @connector_list: list of connector objects | 1030 | * @connector_list: list of connector objects |
1029 | * @num_bridge: number of bridges on this device | ||
1030 | * @bridge_list: list of bridge objects | ||
1031 | * @num_encoder: number of encoders on this device | 1031 | * @num_encoder: number of encoders on this device |
1032 | * @encoder_list: list of encoder objects | 1032 | * @encoder_list: list of encoder objects |
1033 | * @num_overlay_plane: number of overlay planes on this device | 1033 | * @num_overlay_plane: number of overlay planes on this device |
@@ -1072,8 +1072,6 @@ struct drm_mode_config { | |||
1072 | 1072 | ||
1073 | int num_connector; | 1073 | int num_connector; |
1074 | struct list_head connector_list; | 1074 | struct list_head connector_list; |
1075 | int num_bridge; | ||
1076 | struct list_head bridge_list; | ||
1077 | int num_encoder; | 1075 | int num_encoder; |
1078 | struct list_head encoder_list; | 1076 | struct list_head encoder_list; |
1079 | 1077 | ||
@@ -1222,9 +1220,10 @@ extern unsigned int drm_connector_index(struct drm_connector *connector); | |||
1222 | /* helper to unplug all connectors from sysfs for device */ | 1220 | /* helper to unplug all connectors from sysfs for device */ |
1223 | extern void drm_connector_unplug_all(struct drm_device *dev); | 1221 | extern void drm_connector_unplug_all(struct drm_device *dev); |
1224 | 1222 | ||
1225 | extern int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge, | 1223 | extern int drm_bridge_add(struct drm_bridge *bridge); |
1226 | const struct drm_bridge_funcs *funcs); | 1224 | extern void drm_bridge_remove(struct drm_bridge *bridge); |
1227 | extern void drm_bridge_cleanup(struct drm_bridge *bridge); | 1225 | extern struct drm_bridge *of_drm_find_bridge(struct device_node *np); |
1226 | extern int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge); | ||
1228 | 1227 | ||
1229 | extern int drm_encoder_init(struct drm_device *dev, | 1228 | extern int drm_encoder_init(struct drm_device *dev, |
1230 | struct drm_encoder *encoder, | 1229 | struct drm_encoder *encoder, |