diff options
52 files changed, 2625 insertions, 294 deletions
diff --git a/Documentation/devicetree/bindings/video/analog-tv-connector.txt b/Documentation/devicetree/bindings/video/analog-tv-connector.txt new file mode 100644 index 000000000000..0218fcdc1299 --- /dev/null +++ b/Documentation/devicetree/bindings/video/analog-tv-connector.txt @@ -0,0 +1,25 @@ +Analog TV Connector +=================== + +Required properties: +- compatible: "composite-connector" or "svideo-connector" + +Optional properties: +- label: a symbolic name for the connector + +Required nodes: +- Video port for TV input + +Example +------- + +tv: connector { + compatible = "composite-connector"; + label = "tv"; + + port { + tv_connector_in: endpoint { + remote-endpoint = <&venc_out>; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/video/dvi-connector.txt b/Documentation/devicetree/bindings/video/dvi-connector.txt new file mode 100644 index 000000000000..fc53f7c60bc6 --- /dev/null +++ b/Documentation/devicetree/bindings/video/dvi-connector.txt @@ -0,0 +1,35 @@ +DVI Connector +============== + +Required properties: +- compatible: "dvi-connector" + +Optional properties: +- label: a symbolic name for the connector +- ddc-i2c-bus: phandle to the i2c bus that is connected to DVI DDC +- analog: the connector has DVI analog pins +- digital: the connector has DVI digital pins +- dual-link: the connector has pins for DVI dual-link + +Required nodes: +- Video port for DVI input + +Note: One (or both) of 'analog' or 'digital' must be set. + +Example +------- + +dvi0: connector@0 { + compatible = "dvi-connector"; + label = "dvi"; + + digital; + + ddc-i2c-bus = <&i2c3>; + + port { + dvi_connector_in: endpoint { + remote-endpoint = <&tfp410_out>; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/video/hdmi-connector.txt b/Documentation/devicetree/bindings/video/hdmi-connector.txt new file mode 100644 index 000000000000..ccccc19e2573 --- /dev/null +++ b/Documentation/devicetree/bindings/video/hdmi-connector.txt @@ -0,0 +1,28 @@ +HDMI Connector +============== + +Required properties: +- compatible: "hdmi-connector" +- type: the HDMI connector type: "a", "b", "c", "d" or "e" + +Optional properties: +- label: a symbolic name for the connector + +Required nodes: +- Video port for HDMI input + +Example +------- + +hdmi0: connector@1 { + compatible = "hdmi-connector"; + label = "hdmi"; + + type = "a"; + + port { + hdmi_connector_in: endpoint { + remote-endpoint = <&tpd12s015_out>; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/video/panel-dsi-cm.txt b/Documentation/devicetree/bindings/video/panel-dsi-cm.txt new file mode 100644 index 000000000000..dce48eb9db57 --- /dev/null +++ b/Documentation/devicetree/bindings/video/panel-dsi-cm.txt @@ -0,0 +1,29 @@ +Generic MIPI DSI Command Mode Panel +=================================== + +Required properties: +- compatible: "panel-dsi-cm" + +Optional properties: +- label: a symbolic name for the panel +- reset-gpios: panel reset gpio +- te-gpios: panel TE gpio + +Required nodes: +- Video port for DSI input + +Example +------- + +lcd0: display { + compatible = "tpo,taal", "panel-dsi-cm"; + label = "lcd0"; + + reset-gpios = <&gpio4 6 GPIO_ACTIVE_HIGH>; + + port { + lcd0_in: endpoint { + remote-endpoint = <&dsi1_out_ep>; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/video/sony,acx565akm.txt b/Documentation/devicetree/bindings/video/sony,acx565akm.txt new file mode 100644 index 000000000000..e12333280749 --- /dev/null +++ b/Documentation/devicetree/bindings/video/sony,acx565akm.txt @@ -0,0 +1,30 @@ +Sony ACX565AKM SDI Panel +======================== + +Required properties: +- compatible: "sony,acx565akm" + +Optional properties: +- label: a symbolic name for the panel +- reset-gpios: panel reset gpio + +Required nodes: +- Video port for SDI input + +Example +------- + +acx565akm@2 { + compatible = "sony,acx565akm"; + spi-max-frequency = <6000000>; + reg = <2>; + + label = "lcd"; + reset-gpios = <&gpio3 26 GPIO_ACTIVE_HIGH>; /* 90 */ + + port { + lcd_in: endpoint { + remote-endpoint = <&sdi_out>; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/video/ti,omap-dss.txt b/Documentation/devicetree/bindings/video/ti,omap-dss.txt new file mode 100644 index 000000000000..d5f1a3fe3109 --- /dev/null +++ b/Documentation/devicetree/bindings/video/ti,omap-dss.txt @@ -0,0 +1,211 @@ +Texas Instruments OMAP Display Subsystem +======================================== + +Generic Description +------------------- + +This document is a generic description of the OMAP Display Subsystem bindings. +Binding details for each OMAP SoC version are described in respective binding +documentation. + +The OMAP Display Subsystem (DSS) hardware consists of DSS Core, DISPC module and +a number of encoder modules. All DSS versions contain DSS Core and DISPC, but +the encoder modules vary. + +The DSS Core is the parent of the other DSS modules, and manages clock routing, +integration to the SoC, etc. + +DISPC is the display controller, which reads pixels from the memory and outputs +a RGB pixel stream to encoders. + +The encoder modules encode the received RGB pixel stream to a video output like +HDMI, MIPI DPI, etc. + +Video Ports +----------- + +The DSS Core and the encoders have video port outputs. The structure of the +video ports is described in Documentation/devicetree/bindings/video/video- +ports.txt, and the properties for the ports and endpoints for each encoder are +described in the SoC's DSS binding documentation. + +The video ports are used to describe the connections to external hardware, like +panels or external encoders. + +Aliases +------- + +The board dts file may define aliases for displays to assign "displayX" style +name for each display. If no aliases are defined, a semi-random number is used +for the display. + +Example +------- + +A shortened example of the DSS description for OMAP4, with non-relevant parts +removed, defined in omap4.dtsi: + +dss: dss@58000000 { + compatible = "ti,omap4-dss"; + reg = <0x58000000 0x80>; + status = "disabled"; + ti,hwmods = "dss_core"; + clocks = <&dss_dss_clk>; + clock-names = "fck"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + dispc@58001000 { + compatible = "ti,omap4-dispc"; + reg = <0x58001000 0x1000>; + interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>; + ti,hwmods = "dss_dispc"; + clocks = <&dss_dss_clk>; + clock-names = "fck"; + }; + + hdmi: encoder@58006000 { + compatible = "ti,omap4-hdmi"; + reg = <0x58006000 0x200>, + <0x58006200 0x100>, + <0x58006300 0x100>, + <0x58006400 0x1000>; + reg-names = "wp", "pll", "phy", "core"; + interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + ti,hwmods = "dss_hdmi"; + clocks = <&dss_48mhz_clk>, <&dss_sys_clk>; + clock-names = "fck", "sys_clk"; + }; +}; + +A shortened example of the board description for OMAP4 Panda board, defined in +omap4-panda.dts. + +The Panda board has a DVI and a HDMI connector, and the board contains a TFP410 +chip (MIPI DPI to DVI encoder) and a TPD12S015 chip (HDMI ESD protection & level +shifter). The video pipelines for the connectors are formed as follows: + +DSS Core --(MIPI DPI)--> TFP410 --(DVI)--> DVI Connector +OMAP HDMI --(HDMI)--> TPD12S015 --(HDMI)--> HDMI Connector + +/ { + aliases { + display0 = &dvi0; + display1 = &hdmi0; + }; + + tfp410: encoder@0 { + compatible = "ti,tfp410"; + gpios = <&gpio1 0 GPIO_ACTIVE_LOW>; /* 0, power-down */ + + pinctrl-names = "default"; + pinctrl-0 = <&tfp410_pins>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + tfp410_in: endpoint@0 { + remote-endpoint = <&dpi_out>; + }; + }; + + port@1 { + reg = <1>; + + tfp410_out: endpoint@0 { + remote-endpoint = <&dvi_connector_in>; + }; + }; + }; + }; + + dvi0: connector@0 { + compatible = "dvi-connector"; + label = "dvi"; + + i2c-bus = <&i2c3>; + + port { + dvi_connector_in: endpoint { + remote-endpoint = <&tfp410_out>; + }; + }; + }; + + tpd12s015: encoder@1 { + compatible = "ti,tpd12s015"; + + pinctrl-names = "default"; + pinctrl-0 = <&tpd12s015_pins>; + + gpios = <&gpio2 28 GPIO_ACTIVE_HIGH>, /* 60, CT CP HPD */ + <&gpio2 9 GPIO_ACTIVE_HIGH>, /* 41, LS OE */ + <&gpio2 31 GPIO_ACTIVE_HIGH>; /* 63, HPD */ + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + tpd12s015_in: endpoint@0 { + remote-endpoint = <&hdmi_out>; + }; + }; + + port@1 { + reg = <1>; + + tpd12s015_out: endpoint@0 { + remote-endpoint = <&hdmi_connector_in>; + }; + }; + }; + }; + + hdmi0: connector@1 { + compatible = "hdmi-connector"; + label = "hdmi"; + + port { + hdmi_connector_in: endpoint { + remote-endpoint = <&tpd12s015_out>; + }; + }; + }; +}; + +&dss { + status = "ok"; + + pinctrl-names = "default"; + pinctrl-0 = <&dss_dpi_pins>; + + port { + dpi_out: endpoint { + remote-endpoint = <&tfp410_in>; + data-lines = <24>; + }; + }; +}; + +&hdmi { + status = "ok"; + vdda-supply = <&vdac>; + + pinctrl-names = "default"; + pinctrl-0 = <&dss_hdmi_pins>; + + port { + hdmi_out: endpoint { + remote-endpoint = <&tpd12s015_in>; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/video/ti,omap2-dss.txt b/Documentation/devicetree/bindings/video/ti,omap2-dss.txt new file mode 100644 index 000000000000..fa8bb2ed1170 --- /dev/null +++ b/Documentation/devicetree/bindings/video/ti,omap2-dss.txt @@ -0,0 +1,54 @@ +Texas Instruments OMAP2 Display Subsystem +========================================= + +See Documentation/devicetree/bindings/video/ti,omap-dss.txt for generic +description about OMAP Display Subsystem bindings. + +DSS Core +-------- + +Required properties: +- compatible: "ti,omap2-dss" +- reg: address and length of the register space +- ti,hwmods: "dss_core" + +Optional nodes: +- Video port for DPI output + +DPI Endpoint required properties: +- data-lines: number of lines used + + +DISPC +----- + +Required properties: +- compatible: "ti,omap2-dispc" +- reg: address and length of the register space +- ti,hwmods: "dss_dispc" +- interrupts: the DISPC interrupt + + +RFBI +---- + +Required properties: +- compatible: "ti,omap2-rfbi" +- reg: address and length of the register space +- ti,hwmods: "dss_rfbi" + + +VENC +---- + +Required properties: +- compatible: "ti,omap2-venc" +- reg: address and length of the register space +- ti,hwmods: "dss_venc" +- vdda-supply: power supply for DAC + +VENC Endpoint required properties: + +Required properties: +- ti,invert-polarity: invert the polarity of the video signal +- ti,channels: 1 for composite, 2 for s-video diff --git a/Documentation/devicetree/bindings/video/ti,omap3-dss.txt b/Documentation/devicetree/bindings/video/ti,omap3-dss.txt new file mode 100644 index 000000000000..0023fa4b1328 --- /dev/null +++ b/Documentation/devicetree/bindings/video/ti,omap3-dss.txt @@ -0,0 +1,83 @@ +Texas Instruments OMAP3 Display Subsystem +========================================= + +See Documentation/devicetree/bindings/video/ti,omap-dss.txt for generic +description about OMAP Display Subsystem bindings. + +DSS Core +-------- + +Required properties: +- compatible: "ti,omap3-dss" +- reg: address and length of the register space +- ti,hwmods: "dss_core" +- clocks: handle to fclk +- clock-names: "fck" + +Optional nodes: +- Video ports: + - Port 0: DPI output + - Port 1: SDI output + +DPI Endpoint required properties: +- data-lines: number of lines used + +SDI Endpoint required properties: +- datapairs: number of datapairs used + + +DISPC +----- + +Required properties: +- compatible: "ti,omap3-dispc" +- reg: address and length of the register space +- ti,hwmods: "dss_dispc" +- interrupts: the DISPC interrupt +- clocks: handle to fclk +- clock-names: "fck" + + +RFBI +---- + +Required properties: +- compatible: "ti,omap3-rfbi" +- reg: address and length of the register space +- ti,hwmods: "dss_rfbi" +- clocks: handles to fclk and iclk +- clock-names: "fck", "ick" + + +VENC +---- + +Required properties: +- compatible: "ti,omap3-venc" +- reg: address and length of the register space +- ti,hwmods: "dss_venc" +- vdda-supply: power supply for DAC +- clocks: handle to fclk +- clock-names: "fck" + +VENC Endpoint required properties: +- ti,invert-polarity: invert the polarity of the video signal +- ti,channels: 1 for composite, 2 for s-video + + +DSI +--- + +Required properties: +- compatible: "ti,omap3-dsi" +- reg: addresses and lengths of the register spaces for 'proto', 'phy' and 'pll' +- reg-names: "proto", "phy", "pll" +- interrupts: the DSI interrupt line +- ti,hwmods: "dss_dsi1" +- vdd-supply: power supply for DSI +- clocks: handles to fclk and pll clock +- clock-names: "fck", "sys_clk" + +DSI Endpoint required properties: +- lanes: list of pin numbers for the DSI lanes: CLK+, CLK-, DATA0+, DATA0-, + DATA1+, DATA1-, ... diff --git a/Documentation/devicetree/bindings/video/ti,omap4-dss.txt b/Documentation/devicetree/bindings/video/ti,omap4-dss.txt new file mode 100644 index 000000000000..f85d6fcfa705 --- /dev/null +++ b/Documentation/devicetree/bindings/video/ti,omap4-dss.txt @@ -0,0 +1,111 @@ +Texas Instruments OMAP4 Display Subsystem +========================================= + +See Documentation/devicetree/bindings/video/ti,omap-dss.txt for generic +description about OMAP Display Subsystem bindings. + +DSS Core +-------- + +Required properties: +- compatible: "ti,omap4-dss" +- reg: address and length of the register space +- ti,hwmods: "dss_core" +- clocks: handle to fclk +- clock-names: "fck" + +Required nodes: +- DISPC + +Optional nodes: +- DSS Submodules: RFBI, VENC, DSI, HDMI +- Video port for DPI output + +DPI Endpoint required properties: +- data-lines: number of lines used + + +DISPC +----- + +Required properties: +- compatible: "ti,omap4-dispc" +- reg: address and length of the register space +- ti,hwmods: "dss_dispc" +- interrupts: the DISPC interrupt +- clocks: handle to fclk +- clock-names: "fck" + + +RFBI +---- + +Required properties: +- compatible: "ti,omap4-rfbi" +- reg: address and length of the register space +- ti,hwmods: "dss_rfbi" +- clocks: handles to fclk and iclk +- clock-names: "fck", "ick" + +Optional nodes: +- Video port for RFBI output +- RFBI controlled peripherals + + +VENC +---- + +Required properties: +- compatible: "ti,omap4-venc" +- reg: address and length of the register space +- ti,hwmods: "dss_venc" +- vdda-supply: power supply for DAC +- clocks: handle to fclk +- clock-names: "fck" + +Optional nodes: +- Video port for VENC output + +VENC Endpoint required properties: +- ti,invert-polarity: invert the polarity of the video signal +- ti,channels: 1 for composite, 2 for s-video + + +DSI +--- + +Required properties: +- compatible: "ti,omap4-dsi" +- reg: addresses and lengths of the register spaces for 'proto', 'phy' and 'pll' +- reg-names: "proto", "phy", "pll" +- interrupts: the DSI interrupt line +- ti,hwmods: "dss_dsi1" or "dss_dsi2" +- vdd-supply: power supply for DSI +- clocks: handles to fclk and pll clock +- clock-names: "fck", "sys_clk" + +Optional nodes: +- Video port for DSI output +- DSI controlled peripherals + +DSI Endpoint required properties: +- lanes: list of pin numbers for the DSI lanes: CLK+, CLK-, DATA0+, DATA0-, + DATA1+, DATA1-, ... + + +HDMI +---- + +Required properties: +- compatible: "ti,omap4-hdmi" +- reg: addresses and lengths of the register spaces for 'wp', 'pll', 'phy', + 'core' +- reg-names: "wp", "pll", "phy", "core" +- interrupts: the HDMI interrupt line +- ti,hwmods: "dss_hdmi" +- vdda-supply: vdda power supply +- clocks: handles to fclk and pll clock +- clock-names: "fck", "sys_clk" + +Optional nodes: +- Video port for HDMI output diff --git a/Documentation/devicetree/bindings/video/ti,tfp410.txt b/Documentation/devicetree/bindings/video/ti,tfp410.txt new file mode 100644 index 000000000000..2cbe32a3d0bb --- /dev/null +++ b/Documentation/devicetree/bindings/video/ti,tfp410.txt @@ -0,0 +1,41 @@ +TFP410 DPI to DVI encoder +========================= + +Required properties: +- compatible: "ti,tfp410" + +Optional properties: +- powerdown-gpios: power-down gpio + +Required nodes: +- Video port 0 for DPI input +- Video port 1 for DVI output + +Example +------- + +tfp410: encoder@0 { + compatible = "ti,tfp410"; + powerdown-gpios = <&twl_gpio 2 GPIO_ACTIVE_LOW>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + tfp410_in: endpoint@0 { + remote-endpoint = <&dpi_out>; + }; + }; + + port@1 { + reg = <1>; + + tfp410_out: endpoint@0 { + remote-endpoint = <&dvi_connector_in>; + }; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/video/ti,tpd12s015.txt b/Documentation/devicetree/bindings/video/ti,tpd12s015.txt new file mode 100644 index 000000000000..26e6d32e3f20 --- /dev/null +++ b/Documentation/devicetree/bindings/video/ti,tpd12s015.txt @@ -0,0 +1,44 @@ +TPD12S015 HDMI level shifter and ESD protection chip +==================================================== + +Required properties: +- compatible: "ti,tpd12s015" + +Optional properties: +- gpios: CT CP HPD, LS OE and HPD gpios + +Required nodes: +- Video port 0 for HDMI input +- Video port 1 for HDMI output + +Example +------- + +tpd12s015: encoder@1 { + compatible = "ti,tpd12s015"; + + gpios = <&gpio2 28 GPIO_ACTIVE_HIGH>, /* 60, CT CP HPD */ + <&gpio2 9 GPIO_ACTIVE_HIGH>, /* 41, LS OE */ + <&gpio2 31 GPIO_ACTIVE_HIGH>; /* 63, HPD */ + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + tpd12s015_in: endpoint@0 { + remote-endpoint = <&hdmi_out>; + }; + }; + + port@1 { + reg = <1>; + + tpd12s015_out: endpoint@0 { + remote-endpoint = <&hdmi_connector_in>; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/omap2.dtsi b/arch/arm/boot/dts/omap2.dtsi index 5377ddf83bf8..22f35ea142c1 100644 --- a/arch/arm/boot/dts/omap2.dtsi +++ b/arch/arm/boot/dts/omap2.dtsi @@ -271,5 +271,36 @@ ti,hwmods = "timer12"; ti,timer-pwm; }; + + dss: dss@48050000 { + compatible = "ti,omap2-dss"; + reg = <0x48050000 0x400>; + status = "disabled"; + ti,hwmods = "dss_core"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + dispc@48050400 { + compatible = "ti,omap2-dispc"; + reg = <0x48050400 0x400>; + interrupts = <25>; + ti,hwmods = "dss_dispc"; + }; + + rfbi: encoder@48050800 { + compatible = "ti,omap2-rfbi"; + reg = <0x48050800 0x400>; + status = "disabled"; + ti,hwmods = "dss_rfbi"; + }; + + venc: encoder@48050c00 { + compatible = "ti,omap2-venc"; + reg = <0x48050c00 0x400>; + status = "disabled"; + ti,hwmods = "dss_venc"; + }; + }; }; }; diff --git a/arch/arm/boot/dts/omap3-beagle-xm.dts b/arch/arm/boot/dts/omap3-beagle-xm.dts index cba357023878..cf0be662297e 100644 --- a/arch/arm/boot/dts/omap3-beagle-xm.dts +++ b/arch/arm/boot/dts/omap3-beagle-xm.dts @@ -24,6 +24,11 @@ reg = <0x80000000 0x20000000>; /* 512 MB */ }; + aliases { + display0 = &dvi0; + display1 = &tv0; + }; + leds { compatible = "gpio-leds"; @@ -86,6 +91,60 @@ reset-gpios = <&gpio5 19 GPIO_ACTIVE_LOW>; /* gpio_147 */ vcc-supply = <&hsusb2_power>; }; + + tfp410: encoder@0 { + compatible = "ti,tfp410"; + powerdown-gpios = <&twl_gpio 2 GPIO_ACTIVE_LOW>; + + /* XXX pinctrl from twl */ + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + tfp410_in: endpoint@0 { + remote-endpoint = <&dpi_out>; + }; + }; + + port@1 { + reg = <1>; + + tfp410_out: endpoint@0 { + remote-endpoint = <&dvi_connector_in>; + }; + }; + }; + }; + + dvi0: connector@0 { + compatible = "dvi-connector"; + label = "dvi"; + + digital; + + ddc-i2c-bus = <&i2c3>; + + port { + dvi_connector_in: endpoint { + remote-endpoint = <&tfp410_out>; + }; + }; + }; + + tv0: connector@1 { + compatible = "svideo-connector"; + label = "tv"; + + port { + tv_connector_in: endpoint { + remote-endpoint = <&venc_out>; + }; + }; + }; }; &omap3_pmx_wkup { @@ -94,6 +153,17 @@ 0x0e (PIN_INPUT | PIN_OFF_WAKEUPENABLE | MUX_MODE4) /* sys_boot2.gpio_4 */ >; }; + + dss_dpi_pins2: pinmux_dss_dpi_pins1 { + pinctrl-single,pins = < + 0x0a (PIN_OUTPUT | MUX_MODE3) /* sys_boot0.dss_data18 */ + 0x0c (PIN_OUTPUT | MUX_MODE3) /* sys_boot1.dss_data19 */ + 0x10 (PIN_OUTPUT | MUX_MODE3) /* sys_boot3.dss_data20 */ + 0x12 (PIN_OUTPUT | MUX_MODE3) /* sys_boot4.dss_data21 */ + 0x14 (PIN_OUTPUT | MUX_MODE3) /* sys_boot5.dss_data22 */ + 0x16 (PIN_OUTPUT | MUX_MODE3) /* sys_boot6.dss_data23 */ + >; + }; }; &omap3_pmx_core { @@ -119,6 +189,35 @@ OMAP3_CORE1_IOPAD(0x21de, PIN_INPUT_PULLDOWN | MUX_MODE3) /* mcspi2_cs1.hsusb2_data3 */ >; }; + + dss_dpi_pins1: pinmux_dss_dpi_pins2 { + pinctrl-single,pins = < + OMAP3_CORE1_IOPAD(0x20d4, PIN_OUTPUT | MUX_MODE0) /* dss_pclk.dss_pclk */ + OMAP3_CORE1_IOPAD(0x20d6, PIN_OUTPUT | MUX_MODE0) /* dss_hsync.dss_hsync */ + OMAP3_CORE1_IOPAD(0x20d8, PIN_OUTPUT | MUX_MODE0) /* dss_vsync.dss_vsync */ + OMAP3_CORE1_IOPAD(0x20da, PIN_OUTPUT | MUX_MODE0) /* dss_acbias.dss_acbias */ + + OMAP3_CORE1_IOPAD(0x20e8, PIN_OUTPUT | MUX_MODE0) /* dss_data6.dss_data6 */ + OMAP3_CORE1_IOPAD(0x20ea, PIN_OUTPUT | MUX_MODE0) /* dss_data7.dss_data7 */ + OMAP3_CORE1_IOPAD(0x20ec, PIN_OUTPUT | MUX_MODE0) /* dss_data8.dss_data8 */ + OMAP3_CORE1_IOPAD(0x20ee, PIN_OUTPUT | MUX_MODE0) /* dss_data9.dss_data9 */ + OMAP3_CORE1_IOPAD(0x20f0, PIN_OUTPUT | MUX_MODE0) /* dss_data10.dss_data10 */ + OMAP3_CORE1_IOPAD(0x20f2, PIN_OUTPUT | MUX_MODE0) /* dss_data11.dss_data11 */ + OMAP3_CORE1_IOPAD(0x20f4, PIN_OUTPUT | MUX_MODE0) /* dss_data12.dss_data12 */ + OMAP3_CORE1_IOPAD(0x20f6, PIN_OUTPUT | MUX_MODE0) /* dss_data13.dss_data13 */ + OMAP3_CORE1_IOPAD(0x20f8, PIN_OUTPUT | MUX_MODE0) /* dss_data14.dss_data14 */ + OMAP3_CORE1_IOPAD(0x20fa, PIN_OUTPUT | MUX_MODE0) /* dss_data15.dss_data15 */ + OMAP3_CORE1_IOPAD(0x20fc, PIN_OUTPUT | MUX_MODE0) /* dss_data16.dss_data16 */ + OMAP3_CORE1_IOPAD(0x20fe, PIN_OUTPUT | MUX_MODE0) /* dss_data17.dss_data17 */ + + OMAP3_CORE1_IOPAD(0x2100, PIN_OUTPUT | MUX_MODE3) /* dss_data18.dss_data0 */ + OMAP3_CORE1_IOPAD(0x2102, PIN_OUTPUT | MUX_MODE3) /* dss_data19.dss_data1 */ + OMAP3_CORE1_IOPAD(0x2104, PIN_OUTPUT | MUX_MODE3) /* dss_data20.dss_data2 */ + OMAP3_CORE1_IOPAD(0x2106, PIN_OUTPUT | MUX_MODE3) /* dss_data21.dss_data3 */ + OMAP3_CORE1_IOPAD(0x2108, PIN_OUTPUT | MUX_MODE3) /* dss_data22.dss_data4 */ + OMAP3_CORE1_IOPAD(0x210a, PIN_OUTPUT | MUX_MODE3) /* dss_data23.dss_data5 */ + >; + }; }; &omap3_pmx_core2 { @@ -164,15 +263,6 @@ &i2c3 { clock-frequency = <100000>; - - /* - * Display monitor features are burnt in the EEPROM - * as EDID data. - */ - eeprom@50 { - compatible = "ti,eeprom"; - reg = <0x50>; - }; }; &mmc1 { @@ -238,3 +328,33 @@ &mcbsp2 { status = "okay"; }; + +&dss { + status = "ok"; + + pinctrl-names = "default"; + pinctrl-0 = < + &dss_dpi_pins1 + &dss_dpi_pins2 + >; + + port { + dpi_out: endpoint { + remote-endpoint = <&tfp410_in>; + data-lines = <24>; + }; + }; +}; + +&venc { + status = "ok"; + + vdda-supply = <&vdac>; + + port { + venc_out: endpoint { + remote-endpoint = <&tv_connector_in>; + ti,channels = <2>; + }; + }; +}; diff --git a/arch/arm/boot/dts/omap3-beagle.dts b/arch/arm/boot/dts/omap3-beagle.dts index d01e9a76c5da..3c3e6da1deac 100644 --- a/arch/arm/boot/dts/omap3-beagle.dts +++ b/arch/arm/boot/dts/omap3-beagle.dts @@ -24,6 +24,11 @@ reg = <0x80000000 0x10000000>; /* 256 MB */ }; + aliases { + display0 = &dvi0; + display1 = &tv0; + }; + leds { compatible = "gpio-leds"; pmu_stat { @@ -80,6 +85,61 @@ }; }; + + tfp410: encoder@0 { + compatible = "ti,tfp410"; + powerdown-gpios = <&gpio6 10 GPIO_ACTIVE_LOW>; /* gpio_170 */ + + pinctrl-names = "default"; + pinctrl-0 = <&tfp410_pins>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + tfp410_in: endpoint@0 { + remote-endpoint = <&dpi_out>; + }; + }; + + port@1 { + reg = <1>; + + tfp410_out: endpoint@0 { + remote-endpoint = <&dvi_connector_in>; + }; + }; + }; + }; + + dvi0: connector@0 { + compatible = "dvi-connector"; + label = "dvi"; + + digital; + + ddc-i2c-bus = <&i2c3>; + + port { + dvi_connector_in: endpoint { + remote-endpoint = <&tfp410_out>; + }; + }; + }; + + tv0: connector@1 { + compatible = "svideo-connector"; + label = "tv"; + + port { + tv_connector_in: endpoint { + remote-endpoint = <&venc_out>; + }; + }; + }; }; &omap3_pmx_wkup { @@ -113,6 +173,45 @@ 0x170 (PIN_OUTPUT | MUX_MODE0) /* uart3_tx_irtx.uart3_tx_irtx */ >; }; + + tfp410_pins: pinmux_tfp410_pins { + pinctrl-single,pins = < + 0x194 (PIN_OUTPUT | MUX_MODE4) /* hdq_sio.gpio_170 */ + >; + }; + + dss_dpi_pins: pinmux_dss_dpi_pins { + pinctrl-single,pins = < + 0x0a4 (PIN_OUTPUT | MUX_MODE0) /* dss_pclk.dss_pclk */ + 0x0a6 (PIN_OUTPUT | MUX_MODE0) /* dss_hsync.dss_hsync */ + 0x0a8 (PIN_OUTPUT | MUX_MODE0) /* dss_vsync.dss_vsync */ + 0x0aa (PIN_OUTPUT | MUX_MODE0) /* dss_acbias.dss_acbias */ + 0x0ac (PIN_OUTPUT | MUX_MODE0) /* dss_data0.dss_data0 */ + 0x0ae (PIN_OUTPUT | MUX_MODE0) /* dss_data1.dss_data1 */ + 0x0b0 (PIN_OUTPUT | MUX_MODE0) /* dss_data2.dss_data2 */ + 0x0b2 (PIN_OUTPUT | MUX_MODE0) /* dss_data3.dss_data3 */ + 0x0b4 (PIN_OUTPUT | MUX_MODE0) /* dss_data4.dss_data4 */ + 0x0b6 (PIN_OUTPUT | MUX_MODE0) /* dss_data5.dss_data5 */ + 0x0b8 (PIN_OUTPUT | MUX_MODE0) /* dss_data6.dss_data6 */ + 0x0ba (PIN_OUTPUT | MUX_MODE0) /* dss_data7.dss_data7 */ + 0x0bc (PIN_OUTPUT | MUX_MODE0) /* dss_data8.dss_data8 */ + 0x0be (PIN_OUTPUT | MUX_MODE0) /* dss_data9.dss_data9 */ + 0x0c0 (PIN_OUTPUT | MUX_MODE0) /* dss_data10.dss_data10 */ + 0x0c2 (PIN_OUTPUT | MUX_MODE0) /* dss_data11.dss_data11 */ + 0x0c4 (PIN_OUTPUT | MUX_MODE0) /* dss_data12.dss_data12 */ + 0x0c6 (PIN_OUTPUT | MUX_MODE0) /* dss_data13.dss_data13 */ + 0x0c8 (PIN_OUTPUT | MUX_MODE0) /* dss_data14.dss_data14 */ + 0x0ca (PIN_OUTPUT | MUX_MODE0) /* dss_data15.dss_data15 */ + 0x0cc (PIN_OUTPUT | MUX_MODE0) /* dss_data16.dss_data16 */ + 0x0ce (PIN_OUTPUT | MUX_MODE0) /* dss_data17.dss_data17 */ + 0x0d0 (PIN_OUTPUT | MUX_MODE0) /* dss_data18.dss_data18 */ + 0x0d2 (PIN_OUTPUT | MUX_MODE0) /* dss_data19.dss_data19 */ + 0x0d4 (PIN_OUTPUT | MUX_MODE0) /* dss_data20.dss_data20 */ + 0x0d6 (PIN_OUTPUT | MUX_MODE0) /* dss_data21.dss_data21 */ + 0x0d8 (PIN_OUTPUT | MUX_MODE0) /* dss_data22.dss_data22 */ + 0x0da (PIN_OUTPUT | MUX_MODE0) /* dss_data23.dss_data23 */ + >; + }; }; &omap3_pmx_core2 { @@ -152,6 +251,10 @@ #include "twl4030.dtsi" #include "twl4030_omap3.dtsi" +&i2c3 { + clock-frequency = <100000>; +}; + &mmc1 { vmmc-supply = <&vmmc1>; vmmc_aux-supply = <&vsim>; @@ -215,3 +318,35 @@ &mcbsp2 { status = "okay"; }; + +/* Needed to power the DPI pins */ +&vpll2 { + regulator-always-on; +}; + +&dss { + status = "ok"; + + pinctrl-names = "default"; + pinctrl-0 = <&dss_dpi_pins>; + + port { + dpi_out: endpoint { + remote-endpoint = <&tfp410_in>; + data-lines = <24>; + }; + }; +}; + +&venc { + status = "ok"; + + vdda-supply = <&vdac>; + + port { + venc_out: endpoint { + remote-endpoint = <&tv_connector_in>; + ti,channels = <2>; + }; + }; +}; diff --git a/arch/arm/boot/dts/omap3-igep0020.dts b/arch/arm/boot/dts/omap3-igep0020.dts index f2779ac75872..7abd64f6ae21 100644 --- a/arch/arm/boot/dts/omap3-igep0020.dts +++ b/arch/arm/boot/dts/omap3-igep0020.dts @@ -61,22 +61,63 @@ reset-gpios = <&gpio1 24 GPIO_ACTIVE_LOW>; /* gpio_24 */ vcc-supply = <&hsusb1_power>; }; + + tfp410: encoder@0 { + compatible = "ti,tfp410"; + powerdown-gpios = <&gpio6 10 GPIO_ACTIVE_LOW>; /* gpio_170 */ + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + tfp410_in: endpoint@0 { + remote-endpoint = <&dpi_out>; + }; + }; + + port@1 { + reg = <1>; + + tfp410_out: endpoint@0 { + remote-endpoint = <&dvi_connector_in>; + }; + }; + }; + }; + + dvi0: connector@0 { + compatible = "dvi-connector"; + label = "dvi"; + + digital; + + ddc-i2c-bus = <&i2c3>; + + port { + dvi_connector_in: endpoint { + remote-endpoint = <&tfp410_out>; + }; + }; + }; }; &omap3_pmx_core { pinctrl-names = "default"; pinctrl-0 = < &tfp410_pins - &dss_pins + &dss_dpi_pins >; - tfp410_pins: tfp410_dvi_pins { + tfp410_pins: pinmux_tfp410_pins { pinctrl-single,pins = < 0x196 (PIN_OUTPUT | MUX_MODE4) /* hdq_sio.gpio_170 */ >; }; - dss_pins: pinmux_dss_dvi_pins { + dss_dpi_pins: pinmux_dss_dpi_pins { pinctrl-single,pins = < 0x0a4 (PIN_OUTPUT | MUX_MODE0) /* dss_pclk.dss_pclk */ 0x0a6 (PIN_OUTPUT | MUX_MODE0) /* dss_hsync.dss_hsync */ @@ -226,3 +267,14 @@ /* Needed for DSS */ regulator-name = "vdds_dsi"; }; + +&dss { + status = "ok"; + + port { + dpi_out: endpoint { + remote-endpoint = <&tfp410_in>; + data-lines = <24>; + }; + }; +}; diff --git a/arch/arm/boot/dts/omap3-n900.dts b/arch/arm/boot/dts/omap3-n900.dts index d1c3d99dc947..1a57b61f5e24 100644 --- a/arch/arm/boot/dts/omap3-n900.dts +++ b/arch/arm/boot/dts/omap3-n900.dts @@ -79,6 +79,17 @@ nxp,enable-gpio = <&gpio3 3 GPIO_ACTIVE_HIGH>; usb-phy = <&usb2_phy>; }; + + tv: connector { + compatible = "composite-connector"; + label = "tv"; + + port { + tv_connector_in: endpoint { + remote-endpoint = <&venc_out>; + }; + }; + }; }; &omap3_pmx_core { @@ -145,11 +156,23 @@ >; }; - display_pins: pinmux_display_pins { + acx565akm_pins: pinmux_acx565akm_pins { pinctrl-single,pins = < 0x0d4 (PIN_OUTPUT | MUX_MODE4) /* RX51_LCD_RESET_GPIO */ >; }; + + dss_sdi_pins: pinmux_dss_sdi_pins { + pinctrl-single,pins = < + 0x0c0 (PIN_OUTPUT | MUX_MODE1) /* dss_data10.sdi_dat1n */ + 0x0c2 (PIN_OUTPUT | MUX_MODE1) /* dss_data11.sdi_dat1p */ + 0x0c4 (PIN_OUTPUT | MUX_MODE1) /* dss_data12.sdi_dat2n */ + 0x0c6 (PIN_OUTPUT | MUX_MODE1) /* dss_data13.sdi_dat2p */ + + 0x0d8 (PIN_OUTPUT | MUX_MODE1) /* dss_data22.sdi_clkp */ + 0x0da (PIN_OUTPUT | MUX_MODE1) /* dss_data23.sdi_clkn */ + >; + }; }; &i2c1 { @@ -561,13 +584,23 @@ spi-max-frequency = <6000000>; reg = <0>; }; - mipid@2 { - compatible = "acx565akm"; + + acx565akm@2 { + compatible = "sony,acx565akm"; spi-max-frequency = <6000000>; reg = <2>; pinctrl-names = "default"; - pinctrl-0 = <&display_pins>; + pinctrl-0 = <&acx565akm_pins>; + + label = "lcd"; + reset-gpios = <&gpio3 26 GPIO_ACTIVE_HIGH>; /* 90 */ + + port { + lcd_in: endpoint { + remote-endpoint = <&sdi_out>; + }; + }; }; }; @@ -593,3 +626,39 @@ pinctrl-names = "default"; pinctrl-0 = <&uart3_pins>; }; + +&dss { + status = "ok"; + + pinctrl-names = "default"; + pinctrl-0 = <&dss_sdi_pins>; + + vdds_sdi-supply = <&vaux1>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + reg = <1>; + + sdi_out: endpoint { + remote-endpoint = <&lcd_in>; + datapairs = <2>; + }; + }; + }; +}; + +&venc { + status = "ok"; + + vdda-supply = <&vdac>; + + port { + venc_out: endpoint { + remote-endpoint = <&tv_connector_in>; + ti,channels = <1>; + }; + }; +}; diff --git a/arch/arm/boot/dts/omap3.dtsi b/arch/arm/boot/dts/omap3.dtsi index a089e6e00457..3d05eff67e25 100644 --- a/arch/arm/boot/dts/omap3.dtsi +++ b/arch/arm/boot/dts/omap3.dtsi @@ -688,6 +688,58 @@ num-eps = <16>; ram-bits = <12>; }; + + dss: dss@48050000 { + compatible = "ti,omap3-dss"; + reg = <0x48050000 0x200>; + status = "disabled"; + ti,hwmods = "dss_core"; + clocks = <&dss1_alwon_fck>; + clock-names = "fck"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + dispc@48050400 { + compatible = "ti,omap3-dispc"; + reg = <0x48050400 0x400>; + interrupts = <25>; + ti,hwmods = "dss_dispc"; + clocks = <&dss1_alwon_fck>; + clock-names = "fck"; + }; + + dsi: encoder@4804fc00 { + compatible = "ti,omap3-dsi"; + reg = <0x4804fc00 0x200>, + <0x4804fe00 0x40>, + <0x4804ff00 0x20>; + reg-names = "proto", "phy", "pll"; + interrupts = <25>; + status = "disabled"; + ti,hwmods = "dss_dsi1"; + clocks = <&dss1_alwon_fck>, <&dss2_alwon_fck>; + clock-names = "fck", "sys_clk"; + }; + + rfbi: encoder@48050800 { + compatible = "ti,omap3-rfbi"; + reg = <0x48050800 0x100>; + status = "disabled"; + ti,hwmods = "dss_rfbi"; + clocks = <&dss1_alwon_fck>, <&dss_ick>; + clock-names = "fck", "ick"; + }; + + venc: encoder@48050c00 { + compatible = "ti,omap3-venc"; + reg = <0x48050c00 0x100>; + status = "disabled"; + ti,hwmods = "dss_venc"; + clocks = <&dss_tv_fck>; + clock-names = "fck"; + }; + }; }; }; diff --git a/arch/arm/boot/dts/omap3430es1-clocks.dtsi b/arch/arm/boot/dts/omap3430es1-clocks.dtsi index 6f31954636a1..4c22f3a7f813 100644 --- a/arch/arm/boot/dts/omap3430es1-clocks.dtsi +++ b/arch/arm/boot/dts/omap3430es1-clocks.dtsi @@ -152,7 +152,7 @@ clocks = <&usb_l4_gate_ick>, <&usb_l4_div_ick>; }; - dss1_alwon_fck_3430es1: dss1_alwon_fck_3430es1 { + dss1_alwon_fck: dss1_alwon_fck_3430es1 { #clock-cells = <0>; compatible = "ti,gate-clock"; clocks = <&dpll4_m4x2_ck>; @@ -161,7 +161,7 @@ ti,set-rate-parent; }; - dss_ick_3430es1: dss_ick_3430es1 { + dss_ick: dss_ick_3430es1 { #clock-cells = <0>; compatible = "ti,omap3-no-wait-interface-clock"; clocks = <&l4_ick>; @@ -184,7 +184,7 @@ dss_clkdm: dss_clkdm { compatible = "ti,clockdomain"; clocks = <&dss_tv_fck>, <&dss_96m_fck>, <&dss2_alwon_fck>, - <&dss1_alwon_fck_3430es1>, <&dss_ick_3430es1>; + <&dss1_alwon_fck>, <&dss_ick>; }; d2d_clkdm: d2d_clkdm { diff --git a/arch/arm/boot/dts/omap36xx-am35xx-omap3430es2plus-clocks.dtsi b/arch/arm/boot/dts/omap36xx-am35xx-omap3430es2plus-clocks.dtsi index af9ae5346bf2..080fb3f4e429 100644 --- a/arch/arm/boot/dts/omap36xx-am35xx-omap3430es2plus-clocks.dtsi +++ b/arch/arm/boot/dts/omap36xx-am35xx-omap3430es2plus-clocks.dtsi @@ -160,7 +160,7 @@ ti,bit-shift = <30>; }; - dss1_alwon_fck_3430es2: dss1_alwon_fck_3430es2 { + dss1_alwon_fck: dss1_alwon_fck_3430es2 { #clock-cells = <0>; compatible = "ti,dss-gate-clock"; clocks = <&dpll4_m4x2_ck>; @@ -169,7 +169,7 @@ ti,set-rate-parent; }; - dss_ick_3430es2: dss_ick_3430es2 { + dss_ick: dss_ick_3430es2 { #clock-cells = <0>; compatible = "ti,omap3-dss-interface-clock"; clocks = <&l4_ick>; @@ -216,7 +216,7 @@ dss_clkdm: dss_clkdm { compatible = "ti,clockdomain"; clocks = <&dss_tv_fck>, <&dss_96m_fck>, <&dss2_alwon_fck>, - <&dss1_alwon_fck_3430es2>, <&dss_ick_3430es2>; + <&dss1_alwon_fck>, <&dss_ick>; }; core_l4_clkdm: core_l4_clkdm { diff --git a/arch/arm/boot/dts/omap36xx-clocks.dtsi b/arch/arm/boot/dts/omap36xx-clocks.dtsi index 2fcf253b677c..6b5280d04a0e 100644 --- a/arch/arm/boot/dts/omap36xx-clocks.dtsi +++ b/arch/arm/boot/dts/omap36xx-clocks.dtsi @@ -70,6 +70,26 @@ }; }; +&dpll4_m2x2_mul_ck { + clock-mult = <1>; +}; + +&dpll4_m3x2_mul_ck { + clock-mult = <1>; +}; + +&dpll4_m4x2_mul_ck { + ti,clock-mult = <1>; +}; + +&dpll4_m5x2_mul_ck { + clock-mult = <1>; +}; + +&dpll4_m6x2_mul_ck { + clock-mult = <1>; +}; + &cm_clockdomains { dpll4_clkdm: dpll4_clkdm { compatible = "ti,clockdomain"; diff --git a/arch/arm/boot/dts/omap36xx.dtsi b/arch/arm/boot/dts/omap36xx.dtsi index ba077cd95e4e..22cf4647087e 100644 --- a/arch/arm/boot/dts/omap36xx.dtsi +++ b/arch/arm/boot/dts/omap36xx.dtsi @@ -72,7 +72,13 @@ }; }; -/include/ "omap36xx-clocks.dtsi" +/* OMAP3630 needs dss_96m_fck for VENC */ +&venc { + clocks = <&dss_tv_fck>, <&dss_96m_fck>; + clock-names = "fck", "tv_dac_clk"; +}; + /include/ "omap34xx-omap36xx-clocks.dtsi" /include/ "omap36xx-omap3430es2plus-clocks.dtsi" /include/ "omap36xx-am35xx-omap3430es2plus-clocks.dtsi" +/include/ "omap36xx-clocks.dtsi" diff --git a/arch/arm/boot/dts/omap3xxx-clocks.dtsi b/arch/arm/boot/dts/omap3xxx-clocks.dtsi index cb04d4b37e7f..12be2b35dae9 100644 --- a/arch/arm/boot/dts/omap3xxx-clocks.dtsi +++ b/arch/arm/boot/dts/omap3xxx-clocks.dtsi @@ -425,10 +425,11 @@ dpll4_m4x2_mul_ck: dpll4_m4x2_mul_ck { #clock-cells = <0>; - compatible = "fixed-factor-clock"; + compatible = "ti,fixed-factor-clock"; clocks = <&dpll4_m4_ck>; - clock-mult = <2>; - clock-div = <1>; + ti,clock-mult = <2>; + ti,clock-div = <1>; + ti,set-rate-parent; }; dpll4_m4x2_ck: dpll4_m4x2_ck { @@ -438,6 +439,7 @@ ti,bit-shift = <0x1d>; reg = <0x0d00>; ti,set-bit-to-disable; + ti,set-rate-parent; }; dpll4_m5_ck: dpll4_m5_ck { diff --git a/arch/arm/boot/dts/omap4-panda-common.dtsi b/arch/arm/boot/dts/omap4-panda-common.dtsi index cbc45cfc44e9..d2c45bfaaa2c 100644 --- a/arch/arm/boot/dts/omap4-panda-common.dtsi +++ b/arch/arm/boot/dts/omap4-panda-common.dtsi @@ -16,6 +16,11 @@ reg = <0x80000000 0x40000000>; /* 1 GB */ }; + aliases { + display0 = &dvi0; + display1 = &hdmi0; + }; + leds: leds { compatible = "gpio-leds"; pinctrl-names = "default"; @@ -100,6 +105,89 @@ startup-delay-us = <70000>; enable-active-high; }; + + tfp410: encoder@0 { + compatible = "ti,tfp410"; + powerdown-gpios = <&gpio1 0 GPIO_ACTIVE_LOW>; /* gpio_0 */ + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + tfp410_in: endpoint@0 { + remote-endpoint = <&dpi_out>; + }; + }; + + port@1 { + reg = <1>; + + tfp410_out: endpoint@0 { + remote-endpoint = <&dvi_connector_in>; + }; + }; + }; + }; + + dvi0: connector@0 { + compatible = "dvi-connector"; + label = "dvi"; + + digital; + + ddc-i2c-bus = <&i2c3>; + + port { + dvi_connector_in: endpoint { + remote-endpoint = <&tfp410_out>; + }; + }; + }; + + tpd12s015: encoder@1 { + compatible = "ti,tpd12s015"; + + gpios = <&gpio2 28 GPIO_ACTIVE_HIGH>, /* 60, CT CP HPD */ + <&gpio2 9 GPIO_ACTIVE_HIGH>, /* 41, LS OE */ + <&gpio2 31 GPIO_ACTIVE_HIGH>; /* 63, HPD */ + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + tpd12s015_in: endpoint@0 { + remote-endpoint = <&hdmi_out>; + }; + }; + + port@1 { + reg = <1>; + + tpd12s015_out: endpoint@0 { + remote-endpoint = <&hdmi_connector_in>; + }; + }; + }; + }; + + hdmi0: connector@1 { + compatible = "hdmi-connector"; + label = "hdmi"; + + type = "a"; + + port { + hdmi_connector_in: endpoint { + remote-endpoint = <&tpd12s015_out>; + }; + }; + }; }; &omap4_pmx_core { @@ -406,3 +494,30 @@ &usbhsehci { phys = <&hsusb1_phy>; }; + +&dss { + status = "ok"; + + port { + dpi_out: endpoint { + remote-endpoint = <&tfp410_in>; + data-lines = <24>; + }; + }; +}; + +&dsi2 { + status = "ok"; + vdd-supply = <&vcxio>; +}; + +&hdmi { + status = "ok"; + vdda-supply = <&vdac>; + + port { + hdmi_out: endpoint { + remote-endpoint = <&tpd12s015_in>; + }; + }; +}; diff --git a/arch/arm/boot/dts/omap4-sdp.dts b/arch/arm/boot/dts/omap4-sdp.dts index 9bbbbec1d63d..48983c8d56c2 100644 --- a/arch/arm/boot/dts/omap4-sdp.dts +++ b/arch/arm/boot/dts/omap4-sdp.dts @@ -19,6 +19,12 @@ reg = <0x80000000 0x40000000>; /* 1 GB */ }; + aliases { + display0 = &lcd0; + display1 = &lcd1; + display2 = &hdmi0; + }; + vdd_eth: fixedregulator-vdd-eth { compatible = "regulator-fixed"; regulator-name = "VDD_ETH"; @@ -153,6 +159,48 @@ startup-delay-us = <70000>; enable-active-high; }; + + tpd12s015: encoder@0 { + compatible = "ti,tpd12s015"; + + gpios = <&gpio2 28 GPIO_ACTIVE_HIGH>, /* 60, CT CP HPD */ + <&gpio2 9 GPIO_ACTIVE_HIGH>, /* 41, LS OE */ + <&gpio2 31 GPIO_ACTIVE_HIGH>; /* 63, HPD */ + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + + tpd12s015_in: endpoint@0 { + remote-endpoint = <&hdmi_out>; + }; + }; + + port@1 { + reg = <1>; + + tpd12s015_out: endpoint@0 { + remote-endpoint = <&hdmi_connector_in>; + }; + }; + }; + }; + + hdmi0: connector@0 { + compatible = "hdmi-connector"; + label = "hdmi"; + + type = "c"; + + port { + hdmi_connector_in: endpoint { + remote-endpoint = <&tpd12s015_out>; + }; + }; + }; }; &omap4_pmx_core { @@ -569,3 +617,68 @@ mode = <3>; power = <50>; }; + +&dss { + status = "ok"; +}; + +&dsi1 { + status = "ok"; + vdd-supply = <&vcxio>; + + port { + dsi1_out_ep: endpoint { + remote-endpoint = <&lcd0_in>; + lanes = <0 1 2 3 4 5>; + }; + }; + + lcd0: display { + compatible = "tpo,taal", "panel-dsi-cm"; + label = "lcd0"; + + reset-gpios = <&gpio4 6 GPIO_ACTIVE_HIGH>; /* 102 */ + + port { + lcd0_in: endpoint { + remote-endpoint = <&dsi1_out_ep>; + }; + }; + }; +}; + +&dsi2 { + status = "ok"; + vdd-supply = <&vcxio>; + + port { + dsi2_out_ep: endpoint { + remote-endpoint = <&lcd1_in>; + lanes = <0 1 2 3 4 5>; + }; + }; + + lcd1: display { + compatible = "tpo,taal", "panel-dsi-cm"; + label = "lcd1"; + + reset-gpios = <&gpio4 8 GPIO_ACTIVE_HIGH>; /* 104 */ + + port { + lcd1_in: endpoint { + remote-endpoint = <&dsi2_out_ep>; + }; + }; + }; +}; + +&hdmi { + status = "ok"; + vdda-supply = <&vdac>; + + port { + hdmi_out: endpoint { + remote-endpoint = <&tpd12s015_in>; + }; + }; +}; diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi index 0769ec57a3f5..2b4c1cbbce33 100644 --- a/arch/arm/boot/dts/omap4.dtsi +++ b/arch/arm/boot/dts/omap4.dtsi @@ -825,6 +825,85 @@ status = "disabled"; }; + + dss: dss@58000000 { + compatible = "ti,omap4-dss"; + reg = <0x58000000 0x80>; + status = "disabled"; + ti,hwmods = "dss_core"; + clocks = <&dss_dss_clk>; + clock-names = "fck"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + dispc@58001000 { + compatible = "ti,omap4-dispc"; + reg = <0x58001000 0x1000>; + interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>; + ti,hwmods = "dss_dispc"; + clocks = <&dss_dss_clk>; + clock-names = "fck"; + }; + + rfbi: encoder@58002000 { + compatible = "ti,omap4-rfbi"; + reg = <0x58002000 0x1000>; + status = "disabled"; + ti,hwmods = "dss_rfbi"; + clocks = <&dss_dss_clk>, <&dss_fck>; + clock-names = "fck", "ick"; + }; + + venc: encoder@58003000 { + compatible = "ti,omap4-venc"; + reg = <0x58003000 0x1000>; + status = "disabled"; + ti,hwmods = "dss_venc"; + clocks = <&dss_tv_clk>; + clock-names = "fck"; + }; + + dsi1: encoder@58004000 { + compatible = "ti,omap4-dsi"; + reg = <0x58004000 0x200>, + <0x58004200 0x40>, + <0x58004300 0x20>; + reg-names = "proto", "phy", "pll"; + interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + ti,hwmods = "dss_dsi1"; + clocks = <&dss_dss_clk>, <&dss_sys_clk>; + clock-names = "fck", "sys_clk"; + }; + + dsi2: encoder@58005000 { + compatible = "ti,omap4-dsi"; + reg = <0x58005000 0x200>, + <0x58005200 0x40>, + <0x58005300 0x20>; + reg-names = "proto", "phy", "pll"; + interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + ti,hwmods = "dss_dsi2"; + clocks = <&dss_dss_clk>, <&dss_sys_clk>; + clock-names = "fck", "sys_clk"; + }; + + hdmi: encoder@58006000 { + compatible = "ti,omap4-hdmi"; + reg = <0x58006000 0x200>, + <0x58006200 0x100>, + <0x58006300 0x100>, + <0x58006400 0x1000>; + reg-names = "wp", "pll", "phy", "core"; + interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>; + status = "disabled"; + ti,hwmods = "dss_hdmi"; + clocks = <&dss_48mhz_clk>, <&dss_sys_clk>; + clock-names = "fck", "sys_clk"; + }; + }; }; }; diff --git a/arch/arm/mach-omap2/board-generic.c b/arch/arm/mach-omap2/board-generic.c index bc6013fbb773..b8920b6bc104 100644 --- a/arch/arm/mach-omap2/board-generic.c +++ b/arch/arm/mach-omap2/board-generic.c @@ -35,7 +35,11 @@ static struct of_device_id omap_dt_match_table[] __initdata = { static void __init omap_generic_init(void) { + omapdss_early_init_of(); + pdata_quirks_init(omap_dt_match_table); + + omapdss_init_of(); } #ifdef CONFIG_SOC_OMAP2420 diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h index a6aae300542c..d88aff7baff8 100644 --- a/arch/arm/mach-omap2/common.h +++ b/arch/arm/mach-omap2/common.h @@ -315,5 +315,8 @@ extern int omap_dss_reset(struct omap_hwmod *); /* SoC specific clock initializer */ int omap_clk_init(void); +int __init omapdss_init_of(void); +void __init omapdss_early_init_of(void); + #endif /* __ASSEMBLER__ */ #endif /* __ARCH_ARM_MACH_OMAP2PLUS_COMMON_H */ diff --git a/arch/arm/mach-omap2/display.c b/arch/arm/mach-omap2/display.c index 93ebb4007ea9..16d33d831287 100644 --- a/arch/arm/mach-omap2/display.c +++ b/arch/arm/mach-omap2/display.c @@ -23,6 +23,9 @@ #include <linux/clk.h> #include <linux/err.h> #include <linux/delay.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/slab.h> #include <video/omapdss.h> #include "omap_hwmod.h" @@ -551,3 +554,166 @@ int omap_dss_reset(struct omap_hwmod *oh) return r; } + +/* list of 'compatible' nodes to convert to omapdss specific */ +static const char * const dss_compat_conv_list[] __initconst = { + "composite-connector", + "dvi-connector", + "hdmi-connector", + "panel-dpi", + "panel-dsi-cm", + "sony,acx565akm", + "svideo-connector", + "ti,tfp410", + "ti,tpd12s015", +}; + +/* prepend compatible string with "omapdss," */ +static __init void omapdss_omapify_node(struct device_node *node, + const char *compat) +{ + char *new_compat; + struct property *prop; + + new_compat = kasprintf(GFP_KERNEL, "omapdss,%s", compat); + + prop = kzalloc(sizeof(*prop), GFP_KERNEL); + + if (!prop) { + pr_err("omapdss_omapify_node: kzalloc failed\n"); + return; + } + + prop->name = "compatible"; + prop->value = new_compat; + prop->length = strlen(new_compat) + 1; + + of_update_property(node, prop); +} + +/* + * As omapdss panel drivers are omapdss specific, but we want to define the + * DT-data in generic manner, we convert the compatible strings of the panel + * nodes from "panel-foo" to "omapdss,panel-foo". This way we can have both + * correct DT data and omapdss specific drivers. + * + * When we get generic panel drivers to the kernel, this will be removed. + */ +void __init omapdss_early_init_of(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(dss_compat_conv_list); ++i) { + const char *compat = dss_compat_conv_list[i]; + struct device_node *node = NULL; + + while ((node = of_find_compatible_node(node, NULL, compat))) { + if (!of_device_is_available(node)) + continue; + + omapdss_omapify_node(node, compat); + } + } +} + +struct device_node * __init omapdss_find_dss_of_node(void) +{ + struct device_node *node; + + node = of_find_compatible_node(NULL, NULL, "ti,omap2-dss"); + if (node) + return node; + + node = of_find_compatible_node(NULL, NULL, "ti,omap3-dss"); + if (node) + return node; + + node = of_find_compatible_node(NULL, NULL, "ti,omap4-dss"); + if (node) + return node; + + return NULL; +} + +int __init omapdss_init_of(void) +{ + int r; + enum omapdss_version ver; + struct device_node *node; + struct platform_device *pdev; + + static struct omap_dss_board_info board_data = { + .dsi_enable_pads = omap_dsi_enable_pads, + .dsi_disable_pads = omap_dsi_disable_pads, + .set_min_bus_tput = omap_dss_set_min_bus_tput, + }; + + /* only create dss helper devices if dss is enabled in the .dts */ + + node = omapdss_find_dss_of_node(); + if (!node) + return 0; + + if (!of_device_is_available(node)) + return 0; + + ver = omap_display_get_version(); + + if (ver == OMAPDSS_VER_UNKNOWN) { + pr_err("DSS not supported on this SoC\n"); + return -ENODEV; + } + + pdev = of_find_device_by_node(node); + + if (!pdev) { + pr_err("Unable to find DSS platform device\n"); + return -ENODEV; + } + + r = of_platform_populate(node, NULL, NULL, &pdev->dev); + if (r) { + pr_err("Unable to populate DSS submodule devices\n"); + return r; + } + + board_data.version = ver; + + omap_display_device.dev.platform_data = &board_data; + + r = platform_device_register(&omap_display_device); + if (r < 0) { + pr_err("Unable to register omapdss device\n"); + return r; + } + + /* create DRM device */ + r = omap_init_drm(); + if (r < 0) { + pr_err("Unable to register omapdrm device\n"); + return r; + } + + /* create vrfb device */ + r = omap_init_vrfb(); + if (r < 0) { + pr_err("Unable to register omapvrfb device\n"); + return r; + } + + /* create FB device */ + r = omap_init_fb(); + if (r < 0) { + pr_err("Unable to register omapfb device\n"); + return r; + } + + /* create V4L2 display device */ + r = omap_init_vout(); + if (r < 0) { + pr_err("Unable to register omap_vout device\n"); + return r; + } + + return 0; +} diff --git a/arch/arm/mach-omap2/display.h b/arch/arm/mach-omap2/display.h index f3d2ce4bc262..7375854b16c7 100644 --- a/arch/arm/mach-omap2/display.h +++ b/arch/arm/mach-omap2/display.h @@ -30,4 +30,7 @@ int omap_init_drm(void); int omap_init_vrfb(void); int omap_init_fb(void); int omap_init_vout(void); + +struct device_node * __init omapdss_find_dss_of_node(void); + #endif diff --git a/arch/arm/mach-omap2/dss-common.c b/arch/arm/mach-omap2/dss-common.c index dadccc91488c..ea2be0f5953b 100644 --- a/arch/arm/mach-omap2/dss-common.c +++ b/arch/arm/mach-omap2/dss-common.c @@ -33,227 +33,5 @@ #include "soc.h" #include "dss-common.h" #include "mux.h" +#include "display.h" -#define HDMI_GPIO_CT_CP_HPD 60 /* HPD mode enable/disable */ -#define HDMI_GPIO_LS_OE 41 /* Level shifter for HDMI */ -#define HDMI_GPIO_HPD 63 /* Hotplug detect */ - -#define PANDA_DVI_TFP410_POWER_DOWN_GPIO 0 - -/* DVI Connector */ -static struct connector_dvi_platform_data omap4_panda_dvi_connector_pdata = { - .name = "dvi", - .source = "tfp410.0", - .i2c_bus_num = 2, -}; - -static struct platform_device omap4_panda_dvi_connector_device = { - .name = "connector-dvi", - .id = 0, - .dev.platform_data = &omap4_panda_dvi_connector_pdata, -}; - -/* TFP410 DPI-to-DVI chip */ -static struct encoder_tfp410_platform_data omap4_panda_tfp410_pdata = { - .name = "tfp410.0", - .source = "dpi.0", - .data_lines = 24, - .power_down_gpio = PANDA_DVI_TFP410_POWER_DOWN_GPIO, -}; - -static struct platform_device omap4_panda_tfp410_device = { - .name = "tfp410", - .id = 0, - .dev.platform_data = &omap4_panda_tfp410_pdata, -}; - -/* HDMI Connector */ -static struct connector_hdmi_platform_data omap4_panda_hdmi_connector_pdata = { - .name = "hdmi", - .source = "tpd12s015.0", -}; - -static struct platform_device omap4_panda_hdmi_connector_device = { - .name = "connector-hdmi", - .id = 0, - .dev.platform_data = &omap4_panda_hdmi_connector_pdata, -}; - -/* TPD12S015 HDMI ESD protection & level shifter chip */ -static struct encoder_tpd12s015_platform_data omap4_panda_tpd_pdata = { - .name = "tpd12s015.0", - .source = "hdmi.0", - - .ct_cp_hpd_gpio = HDMI_GPIO_CT_CP_HPD, - .ls_oe_gpio = HDMI_GPIO_LS_OE, - .hpd_gpio = HDMI_GPIO_HPD, -}; - -static struct platform_device omap4_panda_tpd_device = { - .name = "tpd12s015", - .id = 0, - .dev.platform_data = &omap4_panda_tpd_pdata, -}; - -static struct omap_dss_board_info omap4_panda_dss_data = { - .default_display_name = "dvi", -}; - -void __init omap4_panda_display_init_of(void) -{ - omap_display_init(&omap4_panda_dss_data); - - platform_device_register(&omap4_panda_tfp410_device); - platform_device_register(&omap4_panda_dvi_connector_device); - - platform_device_register(&omap4_panda_tpd_device); - platform_device_register(&omap4_panda_hdmi_connector_device); -} - - -/* OMAP4 Blaze display data */ - -#define DISPLAY_SEL_GPIO 59 /* LCD2/PicoDLP switch */ -#define DLP_POWER_ON_GPIO 40 - -static struct panel_dsicm_platform_data dsi1_panel = { - .name = "lcd", - .source = "dsi.0", - .reset_gpio = 102, - .use_ext_te = false, - .ext_te_gpio = 101, - .pin_config = { - .num_pins = 6, - .pins = { 0, 1, 2, 3, 4, 5 }, - }, -}; - -static struct platform_device sdp4430_lcd_device = { - .name = "panel-dsi-cm", - .id = 0, - .dev.platform_data = &dsi1_panel, -}; - -static struct panel_dsicm_platform_data dsi2_panel = { - .name = "lcd2", - .source = "dsi.1", - .reset_gpio = 104, - .use_ext_te = false, - .ext_te_gpio = 103, - .pin_config = { - .num_pins = 6, - .pins = { 0, 1, 2, 3, 4, 5 }, - }, -}; - -static struct platform_device sdp4430_lcd2_device = { - .name = "panel-dsi-cm", - .id = 1, - .dev.platform_data = &dsi2_panel, -}; - -/* HDMI Connector */ -static struct connector_hdmi_platform_data sdp4430_hdmi_connector_pdata = { - .name = "hdmi", - .source = "tpd12s015.0", -}; - -static struct platform_device sdp4430_hdmi_connector_device = { - .name = "connector-hdmi", - .id = 0, - .dev.platform_data = &sdp4430_hdmi_connector_pdata, -}; - -/* TPD12S015 HDMI ESD protection & level shifter chip */ -static struct encoder_tpd12s015_platform_data sdp4430_tpd_pdata = { - .name = "tpd12s015.0", - .source = "hdmi.0", - - .ct_cp_hpd_gpio = HDMI_GPIO_CT_CP_HPD, - .ls_oe_gpio = HDMI_GPIO_LS_OE, - .hpd_gpio = HDMI_GPIO_HPD, -}; - -static struct platform_device sdp4430_tpd_device = { - .name = "tpd12s015", - .id = 0, - .dev.platform_data = &sdp4430_tpd_pdata, -}; - - -static struct omap_dss_board_info sdp4430_dss_data = { - .default_display_name = "lcd", -}; - -/* - * we select LCD2 by default (instead of Pico DLP) by setting DISPLAY_SEL_GPIO. - * Setting DLP_POWER_ON gpio enables the VDLP_2V5 VDLP_1V8 and VDLP_1V0 rails - * used by picodlp on the 4430sdp platform. Keep this gpio disabled as LCD2 is - * selected by default - */ -void __init omap_4430sdp_display_init_of(void) -{ - int r; - - r = gpio_request_one(DISPLAY_SEL_GPIO, GPIOF_OUT_INIT_HIGH, - "display_sel"); - if (r) - pr_err("%s: Could not get display_sel GPIO\n", __func__); - - r = gpio_request_one(DLP_POWER_ON_GPIO, GPIOF_OUT_INIT_LOW, - "DLP POWER ON"); - if (r) - pr_err("%s: Could not get DLP POWER ON GPIO\n", __func__); - - omap_display_init(&sdp4430_dss_data); - - platform_device_register(&sdp4430_lcd_device); - platform_device_register(&sdp4430_lcd2_device); - - platform_device_register(&sdp4430_tpd_device); - platform_device_register(&sdp4430_hdmi_connector_device); -} - - -/* OMAP3 IGEPv2 data */ - -#define IGEP2_DVI_TFP410_POWER_DOWN_GPIO 170 - -/* DVI Connector */ -static struct connector_dvi_platform_data omap3_igep2_dvi_connector_pdata = { - .name = "dvi", - .source = "tfp410.0", - .i2c_bus_num = 2, -}; - -static struct platform_device omap3_igep2_dvi_connector_device = { - .name = "connector-dvi", - .id = 0, - .dev.platform_data = &omap3_igep2_dvi_connector_pdata, -}; - -/* TFP410 DPI-to-DVI chip */ -static struct encoder_tfp410_platform_data omap3_igep2_tfp410_pdata = { - .name = "tfp410.0", - .source = "dpi.0", - .data_lines = 24, - .power_down_gpio = IGEP2_DVI_TFP410_POWER_DOWN_GPIO, -}; - -static struct platform_device omap3_igep2_tfp410_device = { - .name = "tfp410", - .id = 0, - .dev.platform_data = &omap3_igep2_tfp410_pdata, -}; - -static struct omap_dss_board_info igep2_dss_data = { - .default_display_name = "dvi", -}; - -void __init omap3_igep2_display_init_of(void) -{ - omap_display_init(&igep2_dss_data); - - platform_device_register(&omap3_igep2_tfp410_device); - platform_device_register(&omap3_igep2_dvi_connector_device); -} diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c index b04c5f0fc278..c3b73351cb7a 100644 --- a/arch/arm/mach-omap2/pdata-quirks.c +++ b/arch/arm/mach-omap2/pdata-quirks.c @@ -141,7 +141,6 @@ static void __init omap3_sbc_t3530_legacy_init(void) static void __init omap3_igep0020_legacy_init(void) { - omap3_igep2_display_init_of(); } static void __init omap3_evm_legacy_init(void) @@ -247,14 +246,12 @@ static void __init nokia_n900_legacy_init(void) #ifdef CONFIG_ARCH_OMAP4 static void __init omap4_sdp_legacy_init(void) { - omap_4430sdp_display_init_of(); legacy_init_wl12xx(WL12XX_REFCLOCK_26, WL12XX_TCXOCLOCK_26, 53); } static void __init omap4_panda_legacy_init(void) { - omap4_panda_display_init_of(); legacy_init_wl12xx(WL12XX_REFCLOCK_38, 0, 53); } #endif diff --git a/drivers/video/omap2/displays-new/connector-analog-tv.c b/drivers/video/omap2/displays-new/connector-analog-tv.c index 27f33ef8fca1..5ee3b5505f7f 100644 --- a/drivers/video/omap2/displays-new/connector-analog-tv.c +++ b/drivers/video/omap2/displays-new/connector-analog-tv.c @@ -12,6 +12,7 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/of.h> #include <video/omapdss.h> #include <video/omap-panel-data.h> @@ -42,6 +43,12 @@ static const struct omap_video_timings tvc_pal_timings = { .interlace = true, }; +static const struct of_device_id tvc_of_match[]; + +struct tvc_of_data { + enum omap_dss_venc_type connector_type; +}; + #define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev) static int tvc_connect(struct omap_dss_device *dssdev) @@ -91,8 +98,12 @@ static int tvc_enable(struct omap_dss_device *dssdev) in->ops.atv->set_timings(in, &ddata->timings); - in->ops.atv->set_type(in, ddata->connector_type); - in->ops.atv->invert_vid_out_polarity(in, ddata->invert_polarity); + if (!ddata->dev->of_node) { + in->ops.atv->set_type(in, ddata->connector_type); + + in->ops.atv->invert_vid_out_polarity(in, + ddata->invert_polarity); + } r = in->ops.atv->enable(in); if (r) @@ -205,6 +216,23 @@ static int tvc_probe_pdata(struct platform_device *pdev) return 0; } +static int tvc_probe_of(struct platform_device *pdev) +{ + struct panel_drv_data *ddata = platform_get_drvdata(pdev); + struct device_node *node = pdev->dev.of_node; + struct omap_dss_device *in; + + in = omapdss_of_find_source_for_first_ep(node); + if (IS_ERR(in)) { + dev_err(&pdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + + ddata->in = in; + + return 0; +} + static int tvc_probe(struct platform_device *pdev) { struct panel_drv_data *ddata; @@ -222,6 +250,10 @@ static int tvc_probe(struct platform_device *pdev) r = tvc_probe_pdata(pdev); if (r) return r; + } else if (pdev->dev.of_node) { + r = tvc_probe_of(pdev); + if (r) + return r; } else { return -ENODEV; } @@ -263,12 +295,19 @@ static int __exit tvc_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id tvc_of_match[] = { + { .compatible = "omapdss,svideo-connector", }, + { .compatible = "omapdss,composite-video-connector", }, + {}, +}; + static struct platform_driver tvc_connector_driver = { .probe = tvc_probe, .remove = __exit_p(tvc_remove), .driver = { .name = "connector-analog-tv", .owner = THIS_MODULE, + .of_match_table = tvc_of_match, }, }; diff --git a/drivers/video/omap2/displays-new/connector-dvi.c b/drivers/video/omap2/displays-new/connector-dvi.c index d18e4b8c0731..74de2bc50c4f 100644 --- a/drivers/video/omap2/displays-new/connector-dvi.c +++ b/drivers/video/omap2/displays-new/connector-dvi.c @@ -277,6 +277,37 @@ static int dvic_probe_pdata(struct platform_device *pdev) return 0; } +static int dvic_probe_of(struct platform_device *pdev) +{ + struct panel_drv_data *ddata = platform_get_drvdata(pdev); + struct device_node *node = pdev->dev.of_node; + struct omap_dss_device *in; + struct device_node *adapter_node; + struct i2c_adapter *adapter; + + in = omapdss_of_find_source_for_first_ep(node); + if (IS_ERR(in)) { + dev_err(&pdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + + ddata->in = in; + + adapter_node = of_parse_phandle(node, "ddc-i2c-bus", 0); + if (adapter_node) { + adapter = of_find_i2c_adapter_by_node(adapter_node); + if (adapter == NULL) { + dev_err(&pdev->dev, "failed to parse ddc-i2c-bus\n"); + omap_dss_put_device(ddata->in); + return -EPROBE_DEFER; + } + + ddata->i2c_adapter = adapter; + } + + return 0; +} + static int dvic_probe(struct platform_device *pdev) { struct panel_drv_data *ddata; @@ -293,6 +324,10 @@ static int dvic_probe(struct platform_device *pdev) r = dvic_probe_pdata(pdev); if (r) return r; + } else if (pdev->dev.of_node) { + r = dvic_probe_of(pdev); + if (r) + return r; } else { return -ENODEV; } @@ -342,12 +377,20 @@ static int __exit dvic_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id dvic_of_match[] = { + { .compatible = "omapdss,dvi-connector", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, dvic_of_match); + static struct platform_driver dvi_connector_driver = { .probe = dvic_probe, .remove = __exit_p(dvic_remove), .driver = { .name = "connector-dvi", .owner = THIS_MODULE, + .of_match_table = dvic_of_match, }, }; diff --git a/drivers/video/omap2/displays-new/connector-hdmi.c b/drivers/video/omap2/displays-new/connector-hdmi.c index 9393e2d6473d..29ed21b9dce5 100644 --- a/drivers/video/omap2/displays-new/connector-hdmi.c +++ b/drivers/video/omap2/displays-new/connector-hdmi.c @@ -12,6 +12,7 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/of.h> #include <drm/drm_edid.h> @@ -301,6 +302,23 @@ static int hdmic_probe_pdata(struct platform_device *pdev) return 0; } +static int hdmic_probe_of(struct platform_device *pdev) +{ + struct panel_drv_data *ddata = platform_get_drvdata(pdev); + struct device_node *node = pdev->dev.of_node; + struct omap_dss_device *in; + + in = omapdss_of_find_source_for_first_ep(node); + if (IS_ERR(in)) { + dev_err(&pdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + + ddata->in = in; + + return 0; +} + static int hdmic_probe(struct platform_device *pdev) { struct panel_drv_data *ddata; @@ -318,6 +336,10 @@ static int hdmic_probe(struct platform_device *pdev) r = hdmic_probe_pdata(pdev); if (r) return r; + } else if (pdev->dev.of_node) { + r = hdmic_probe_of(pdev); + if (r) + return r; } else { return -ENODEV; } @@ -359,12 +381,20 @@ static int __exit hdmic_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id hdmic_of_match[] = { + { .compatible = "omapdss,hdmi-connector", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, hdmic_of_match); + static struct platform_driver hdmi_connector_driver = { .probe = hdmic_probe, .remove = __exit_p(hdmic_remove), .driver = { .name = "connector-hdmi", .owner = THIS_MODULE, + .of_match_table = hdmic_of_match, }, }; diff --git a/drivers/video/omap2/displays-new/encoder-tfp410.c b/drivers/video/omap2/displays-new/encoder-tfp410.c index 4a291e756be9..b4e9a42a79e6 100644 --- a/drivers/video/omap2/displays-new/encoder-tfp410.c +++ b/drivers/video/omap2/displays-new/encoder-tfp410.c @@ -13,6 +13,7 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/slab.h> +#include <linux/of_gpio.h> #include <video/omapdss.h> #include <video/omap-panel-data.h> @@ -82,7 +83,8 @@ static int tfp410_enable(struct omap_dss_device *dssdev) return 0; in->ops.dpi->set_timings(in, &ddata->timings); - in->ops.dpi->set_data_lines(in, ddata->data_lines); + if (ddata->data_lines) + in->ops.dpi->set_data_lines(in, ddata->data_lines); r = in->ops.dpi->enable(in); if (r) @@ -179,6 +181,33 @@ static int tfp410_probe_pdata(struct platform_device *pdev) return 0; } +static int tfp410_probe_of(struct platform_device *pdev) +{ + struct panel_drv_data *ddata = platform_get_drvdata(pdev); + struct device_node *node = pdev->dev.of_node; + struct omap_dss_device *in; + int gpio; + + gpio = of_get_named_gpio(node, "powerdown-gpios", 0); + + if (gpio_is_valid(gpio) || gpio == -ENOENT) { + ddata->pd_gpio = gpio; + } else { + dev_err(&pdev->dev, "failed to parse PD gpio\n"); + return gpio; + } + + in = omapdss_of_find_source_for_first_ep(node); + if (IS_ERR(in)) { + dev_err(&pdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + + ddata->in = in; + + return 0; +} + static int tfp410_probe(struct platform_device *pdev) { struct panel_drv_data *ddata; @@ -195,6 +224,10 @@ static int tfp410_probe(struct platform_device *pdev) r = tfp410_probe_pdata(pdev); if (r) return r; + } else if (pdev->dev.of_node) { + r = tfp410_probe_of(pdev); + if (r) + return r; } else { return -ENODEV; } @@ -251,12 +284,20 @@ static int __exit tfp410_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id tfp410_of_match[] = { + { .compatible = "omapdss,ti,tfp410", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, tfp410_of_match); + static struct platform_driver tfp410_driver = { .probe = tfp410_probe, .remove = __exit_p(tfp410_remove), .driver = { .name = "tfp410", .owner = THIS_MODULE, + .of_match_table = tfp410_of_match, }, }; diff --git a/drivers/video/omap2/displays-new/encoder-tpd12s015.c b/drivers/video/omap2/displays-new/encoder-tpd12s015.c index d5c936cb217f..7e33686171e3 100644 --- a/drivers/video/omap2/displays-new/encoder-tpd12s015.c +++ b/drivers/video/omap2/displays-new/encoder-tpd12s015.c @@ -15,6 +15,7 @@ #include <linux/slab.h> #include <linux/gpio.h> #include <linux/platform_device.h> +#include <linux/of_gpio.h> #include <video/omapdss.h> #include <video/omap-panel-data.h> @@ -289,6 +290,49 @@ static int tpd_probe_pdata(struct platform_device *pdev) return 0; } +static int tpd_probe_of(struct platform_device *pdev) +{ + struct panel_drv_data *ddata = platform_get_drvdata(pdev); + struct device_node *node = pdev->dev.of_node; + struct omap_dss_device *in; + int gpio; + + /* CT CP HPD GPIO */ + gpio = of_get_gpio(node, 0); + if (!gpio_is_valid(gpio)) { + dev_err(&pdev->dev, "failed to parse CT CP HPD gpio\n"); + return gpio; + } + ddata->ct_cp_hpd_gpio = gpio; + + /* LS OE GPIO */ + gpio = of_get_gpio(node, 1); + if (gpio_is_valid(gpio) || gpio == -ENOENT) { + ddata->ls_oe_gpio = gpio; + } else { + dev_err(&pdev->dev, "failed to parse LS OE gpio\n"); + return gpio; + } + + /* HPD GPIO */ + gpio = of_get_gpio(node, 2); + if (!gpio_is_valid(gpio)) { + dev_err(&pdev->dev, "failed to parse HPD gpio\n"); + return gpio; + } + ddata->hpd_gpio = gpio; + + in = omapdss_of_find_source_for_first_ep(node); + if (IS_ERR(in)) { + dev_err(&pdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + + ddata->in = in; + + return 0; +} + static int tpd_probe(struct platform_device *pdev) { struct omap_dss_device *in, *dssdev; @@ -307,6 +351,10 @@ static int tpd_probe(struct platform_device *pdev) r = tpd_probe_pdata(pdev); if (r) return r; + } else if (pdev->dev.of_node) { + r = tpd_probe_of(pdev); + if (r) + return r; } else { return -ENODEV; } @@ -379,12 +427,20 @@ static int __exit tpd_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id tpd_of_match[] = { + { .compatible = "omapdss,ti,tpd12s015", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, tpd_of_match); + static struct platform_driver tpd_driver = { .probe = tpd_probe, .remove = __exit_p(tpd_remove), .driver = { .name = "tpd12s015", .owner = THIS_MODULE, + .of_match_table = tpd_of_match, }, }; diff --git a/drivers/video/omap2/displays-new/panel-dsi-cm.c b/drivers/video/omap2/displays-new/panel-dsi-cm.c index f317c878a259..d6f14e8717e8 100644 --- a/drivers/video/omap2/displays-new/panel-dsi-cm.c +++ b/drivers/video/omap2/displays-new/panel-dsi-cm.c @@ -22,6 +22,8 @@ #include <linux/sched.h> #include <linux/slab.h> #include <linux/workqueue.h> +#include <linux/of_device.h> +#include <linux/of_gpio.h> #include <video/omapdss.h> #include <video/omap-panel-data.h> @@ -595,10 +597,13 @@ static int dsicm_power_on(struct panel_drv_data *ddata) .lp_clk_max = 10000000, }; - r = in->ops.dsi->configure_pins(in, &ddata->pin_config); - if (r) { - dev_err(&ddata->pdev->dev, "failed to configure DSI pins\n"); - goto err0; + if (ddata->pin_config.num_pins > 0) { + r = in->ops.dsi->configure_pins(in, &ddata->pin_config); + if (r) { + dev_err(&ddata->pdev->dev, + "failed to configure DSI pins\n"); + goto err0; + } } r = in->ops.dsi->set_config(in, &dsi_config); @@ -1156,6 +1161,41 @@ static int dsicm_probe_pdata(struct platform_device *pdev) return 0; } +static int dsicm_probe_of(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct panel_drv_data *ddata = platform_get_drvdata(pdev); + struct omap_dss_device *in; + int gpio; + + gpio = of_get_named_gpio(node, "reset-gpios", 0); + if (!gpio_is_valid(gpio)) { + dev_err(&pdev->dev, "failed to parse reset gpio\n"); + return gpio; + } + ddata->reset_gpio = gpio; + + gpio = of_get_named_gpio(node, "te-gpios", 0); + if (gpio_is_valid(gpio) || gpio == -ENOENT) { + ddata->ext_te_gpio = gpio; + } else { + dev_err(&pdev->dev, "failed to parse TE gpio\n"); + return gpio; + } + + in = omapdss_of_find_source_for_first_ep(node); + if (IS_ERR(in)) { + dev_err(&pdev->dev, "failed to find video source\n"); + return PTR_ERR(in); + } + + ddata->in = in; + + /* TODO: ulps, backlight */ + + return 0; +} + static int dsicm_probe(struct platform_device *pdev) { struct backlight_properties props; @@ -1178,6 +1218,10 @@ static int dsicm_probe(struct platform_device *pdev) r = dsicm_probe_pdata(pdev); if (r) return r; + } else if (pdev->dev.of_node) { + r = dsicm_probe_of(pdev); + if (r) + return r; } else { return -ENODEV; } @@ -1320,12 +1364,20 @@ static int __exit dsicm_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id dsicm_of_match[] = { + { .compatible = "omapdss,panel-dsi-cm", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, dsicm_of_match); + static struct platform_driver dsicm_driver = { .probe = dsicm_probe, .remove = __exit_p(dsicm_remove), .driver = { .name = "panel-dsi-cm", .owner = THIS_MODULE, + .of_match_table = dsicm_of_match, }, }; diff --git a/drivers/video/omap2/displays-new/panel-sony-acx565akm.c b/drivers/video/omap2/displays-new/panel-sony-acx565akm.c index 27f60ad6b2ab..c7ba4d8b928a 100644 --- a/drivers/video/omap2/displays-new/panel-sony-acx565akm.c +++ b/drivers/video/omap2/displays-new/panel-sony-acx565akm.c @@ -30,6 +30,8 @@ #include <linux/backlight.h> #include <linux/fb.h> #include <linux/gpio.h> +#include <linux/of.h> +#include <linux/of_gpio.h> #include <video/omapdss.h> #include <video/omap-panel-data.h> @@ -547,7 +549,9 @@ static int acx565akm_panel_power_on(struct omap_dss_device *dssdev) dev_dbg(&ddata->spi->dev, "%s\n", __func__); in->ops.sdi->set_timings(in, &ddata->videomode); - in->ops.sdi->set_datapairs(in, ddata->datapairs); + + if (ddata->datapairs > 0) + in->ops.sdi->set_datapairs(in, ddata->datapairs); r = in->ops.sdi->enable(in); if (r) { @@ -726,6 +730,22 @@ static int acx565akm_probe_pdata(struct spi_device *spi) return 0; } +static int acx565akm_probe_of(struct spi_device *spi) +{ + struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev); + struct device_node *np = spi->dev.of_node; + + ddata->reset_gpio = of_get_named_gpio(np, "reset-gpios", 0); + + ddata->in = omapdss_of_find_source_for_first_ep(np); + if (IS_ERR(ddata->in)) { + dev_err(&spi->dev, "failed to find video source\n"); + return PTR_ERR(ddata->in); + } + + return 0; +} + static int acx565akm_probe(struct spi_device *spi) { struct panel_drv_data *ddata; @@ -753,7 +773,12 @@ static int acx565akm_probe(struct spi_device *spi) r = acx565akm_probe_pdata(spi); if (r) return r; + } else if (spi->dev.of_node) { + r = acx565akm_probe_of(spi); + if (r) + return r; } else { + dev_err(&spi->dev, "platform data missing!\n"); return -ENODEV; } @@ -864,10 +889,16 @@ static int acx565akm_remove(struct spi_device *spi) return 0; } +static const struct of_device_id acx565akm_of_match[] = { + { .compatible = "omapdss,sony,acx565akm", }, + {}, +}; + static struct spi_driver acx565akm_driver = { .driver = { .name = "acx565akm", .owner = THIS_MODULE, + .of_match_table = acx565akm_of_match, }, .probe = acx565akm_probe, .remove = acx565akm_remove, diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile index d3aa91bdd6a8..8aec8bda27cc 100644 --- a/drivers/video/omap2/dss/Makefile +++ b/drivers/video/omap2/dss/Makefile @@ -1,7 +1,7 @@ obj-$(CONFIG_OMAP2_DSS) += omapdss.o # Core DSS files omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \ - output.o + output.o dss-of.o # DSS compat layer files omapdss-y += manager.o manager-sysfs.o overlay.o overlay-sysfs.o apply.o \ dispc-compat.o display-sysfs.o diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index aaecbf347748..2bbdb7ff7daf 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -3778,12 +3778,20 @@ static const struct dev_pm_ops dispc_pm_ops = { .runtime_resume = dispc_runtime_resume, }; +static const struct of_device_id dispc_of_match[] = { + { .compatible = "ti,omap2-dispc", }, + { .compatible = "ti,omap3-dispc", }, + { .compatible = "ti,omap4-dispc", }, + {}, +}; + static struct platform_driver omap_dispchw_driver = { .remove = __exit_p(omap_dispchw_remove), .driver = { .name = "omapdss_dispc", .owner = THIS_MODULE, .pm = &dispc_pm_ops, + .of_match_table = dispc_of_match, }, }; diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c index 9f19ae22944c..2412a0dd0c13 100644 --- a/drivers/video/omap2/dss/display.c +++ b/drivers/video/omap2/dss/display.c @@ -26,6 +26,7 @@ #include <linux/module.h> #include <linux/jiffies.h> #include <linux/platform_device.h> +#include <linux/of.h> #include <video/omapdss.h> #include "dss.h" @@ -133,9 +134,32 @@ static int disp_num_counter; int omapdss_register_display(struct omap_dss_device *dssdev) { struct omap_dss_driver *drv = dssdev->driver; + int id; - snprintf(dssdev->alias, sizeof(dssdev->alias), - "display%d", disp_num_counter++); + /* + * Note: this presumes all the displays are either using DT or non-DT, + * which normally should be the case. This also presumes that all + * displays either have an DT alias, or none has. + */ + + if (dssdev->dev->of_node) { + id = of_alias_get_id(dssdev->dev->of_node, "display"); + + if (id < 0) + id = disp_num_counter++; + } else { + id = disp_num_counter++; + } + + snprintf(dssdev->alias, sizeof(dssdev->alias), "display%d", id); + + /* Use 'label' property for name, if it exists */ + if (dssdev->dev->of_node) + of_property_read_string(dssdev->dev->of_node, "label", + &dssdev->name); + + if (dssdev->name == NULL) + dssdev->name = dssdev->alias; if (drv && drv->get_resolution == NULL) drv->get_resolution = omapdss_default_get_resolution; diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index 6c0bb099b7bf..157921db447a 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c @@ -30,6 +30,7 @@ #include <linux/platform_device.h> #include <linux/regulator/consumer.h> #include <linux/string.h> +#include <linux/of.h> #include <video/omapdss.h> @@ -49,6 +50,8 @@ static struct { int data_lines; struct omap_dss_device output; + + bool port_initialized; } dpi; static struct platform_device *dpi_get_dsidev(enum omap_channel channel) @@ -725,3 +728,47 @@ void __exit dpi_uninit_platform_driver(void) { platform_driver_unregister(&omap_dpi_driver); } + +int __init dpi_init_port(struct platform_device *pdev, struct device_node *port) +{ + struct device_node *ep; + u32 datalines; + int r; + + ep = omapdss_of_get_next_endpoint(port, NULL); + if (!ep) + return 0; + + r = of_property_read_u32(ep, "data-lines", &datalines); + if (r) { + DSSERR("failed to parse datalines\n"); + goto err_datalines; + } + + dpi.data_lines = datalines; + + of_node_put(ep); + + dpi.pdev = pdev; + + mutex_init(&dpi.lock); + + dpi_init_output(pdev); + + dpi.port_initialized = true; + + return 0; + +err_datalines: + of_node_put(ep); + + return r; +} + +void __exit dpi_uninit_port(void) +{ + if (!dpi.port_initialized) + return; + + dpi_uninit_output(dpi.pdev); +} diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 0d82f731d2f0..121d1049d0bc 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -38,6 +38,8 @@ #include <linux/slab.h> #include <linux/debugfs.h> #include <linux/pm_runtime.h> +#include <linux/of.h> +#include <linux/of_platform.h> #include <video/omapdss.h> #include <video/mipi_display.h> @@ -386,6 +388,13 @@ struct dsi_packet_sent_handler_data { struct completion *completion; }; +struct dsi_module_id_data { + u32 address; + int id; +}; + +static const struct of_device_id dsi_of_match[]; + #ifdef DSI_PERF_MEASURE static bool dsi_perf; module_param(dsi_perf, bool, 0644); @@ -1151,15 +1160,11 @@ static int dsi_regulator_init(struct platform_device *dsidev) if (dsi->vdds_dsi_reg != NULL) return 0; - vdds_dsi = devm_regulator_get(&dsi->pdev->dev, "vdds_dsi"); - - /* DT HACK: try VCXIO to make omapdss work for o4 sdp/panda */ - if (IS_ERR(vdds_dsi)) - vdds_dsi = devm_regulator_get(&dsi->pdev->dev, "VCXIO"); + vdds_dsi = devm_regulator_get(&dsi->pdev->dev, "vdd"); if (IS_ERR(vdds_dsi)) { if (PTR_ERR(vdds_dsi) != -EPROBE_DEFER) - DSSERR("can't get VDDS_DSI regulator\n"); + DSSERR("can't get DSI VDD regulator\n"); return PTR_ERR(vdds_dsi); } @@ -5370,12 +5375,69 @@ static void dsi_uninit_output(struct platform_device *dsidev) omapdss_unregister_output(out); } +static int dsi_probe_of(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct dsi_data *dsi = dsi_get_dsidrv_data(pdev); + struct property *prop; + u32 lane_arr[10]; + int len, num_pins; + int r, i; + struct device_node *ep; + struct omap_dsi_pin_config pin_cfg; + + ep = omapdss_of_get_first_endpoint(node); + if (!ep) + return 0; + + prop = of_find_property(ep, "lanes", &len); + if (prop == NULL) { + dev_err(&pdev->dev, "failed to find lane data\n"); + r = -EINVAL; + goto err; + } + + num_pins = len / sizeof(u32); + + if (num_pins < 4 || num_pins % 2 != 0 || + num_pins > dsi->num_lanes_supported * 2) { + dev_err(&pdev->dev, "bad number of lanes\n"); + r = -EINVAL; + goto err; + } + + r = of_property_read_u32_array(ep, "lanes", lane_arr, num_pins); + if (r) { + dev_err(&pdev->dev, "failed to read lane data\n"); + goto err; + } + + pin_cfg.num_pins = num_pins; + for (i = 0; i < num_pins; ++i) + pin_cfg.pins[i] = (int)lane_arr[i]; + + r = dsi_configure_pins(&dsi->output, &pin_cfg); + if (r) { + dev_err(&pdev->dev, "failed to configure pins"); + goto err; + } + + of_node_put(ep); + + return 0; + +err: + of_node_put(ep); + return r; +} + /* DSI1 HW IP initialisation */ static int omap_dsihw_probe(struct platform_device *dsidev) { u32 rev; int r, i; struct dsi_data *dsi; + struct resource *dsi_mem; struct resource *res; struct resource temp_res; @@ -5383,7 +5445,6 @@ static int omap_dsihw_probe(struct platform_device *dsidev) if (!dsi) return -ENOMEM; - dsi->module_id = dsidev->id; dsi->pdev = dsidev; dev_set_drvdata(&dsidev->dev, dsi); @@ -5421,6 +5482,8 @@ static int omap_dsihw_probe(struct platform_device *dsidev) res = &temp_res; } + dsi_mem = res; + dsi->proto_base = devm_ioremap(&dsidev->dev, res->start, resource_size(res)); if (!dsi->proto_base) { @@ -5481,6 +5544,31 @@ static int omap_dsihw_probe(struct platform_device *dsidev) return r; } + if (dsidev->dev.of_node) { + const struct of_device_id *match; + const struct dsi_module_id_data *d; + + match = of_match_node(dsi_of_match, dsidev->dev.of_node); + if (!match) { + DSSERR("unsupported DSI module\n"); + return -ENODEV; + } + + d = match->data; + + while (d->address != 0 && d->address != dsi_mem->start) + d++; + + if (d->address == 0) { + DSSERR("unsupported DSI module\n"); + return -ENODEV; + } + + dsi->module_id = d->id; + } else { + dsi->module_id = dsidev->id; + } + /* DSI VCs initialization */ for (i = 0; i < ARRAY_SIZE(dsi->vc); i++) { dsi->vc[i].source = DSI_VC_SOURCE_L4; @@ -5516,6 +5604,19 @@ static int omap_dsihw_probe(struct platform_device *dsidev) dsi_init_output(dsidev); + if (dsidev->dev.of_node) { + r = dsi_probe_of(dsidev); + if (r) { + DSSERR("Invalid DSI DT data\n"); + goto err_probe_of; + } + + r = of_platform_populate(dsidev->dev.of_node, NULL, NULL, + &dsidev->dev); + if (r) + DSSERR("Failed to populate DSI child devices: %d\n", r); + } + dsi_runtime_put(dsidev); if (dsi->module_id == 0) @@ -5529,17 +5630,31 @@ static int omap_dsihw_probe(struct platform_device *dsidev) else if (dsi->module_id == 1) dss_debugfs_create_file("dsi2_irqs", dsi2_dump_irqs); #endif + return 0; +err_probe_of: + dsi_uninit_output(dsidev); + dsi_runtime_put(dsidev); + err_runtime_get: pm_runtime_disable(&dsidev->dev); return r; } +static int dsi_unregister_child(struct device *dev, void *data) +{ + struct platform_device *pdev = to_platform_device(dev); + platform_device_unregister(pdev); + return 0; +} + static int __exit omap_dsihw_remove(struct platform_device *dsidev) { struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); + device_for_each_child(&dsidev->dev, NULL, dsi_unregister_child); + WARN_ON(dsi->scp_clk_refcount > 0); dsi_uninit_output(dsidev); @@ -5577,6 +5692,23 @@ static const struct dev_pm_ops dsi_pm_ops = { .runtime_resume = dsi_runtime_resume, }; +static const struct dsi_module_id_data dsi_of_data_omap3[] = { + { .address = 0x4804fc00, .id = 0, }, + { }, +}; + +static const struct dsi_module_id_data dsi_of_data_omap4[] = { + { .address = 0x58004000, .id = 0, }, + { .address = 0x58005000, .id = 1, }, + { }, +}; + +static const struct of_device_id dsi_of_match[] = { + { .compatible = "ti,omap3-dsi", .data = dsi_of_data_omap3, }, + { .compatible = "ti,omap4-dsi", .data = dsi_of_data_omap4, }, + {}, +}; + static struct platform_driver omap_dsihw_driver = { .probe = omap_dsihw_probe, .remove = __exit_p(omap_dsihw_remove), @@ -5584,6 +5716,7 @@ static struct platform_driver omap_dsihw_driver = { .name = "omapdss_dsi", .owner = THIS_MODULE, .pm = &dsi_pm_ops, + .of_match_table = dsi_of_match, }, }; diff --git a/drivers/video/omap2/dss/dss-of.c b/drivers/video/omap2/dss/dss-of.c new file mode 100644 index 000000000000..a4b20aaf6142 --- /dev/null +++ b/drivers/video/omap2/dss/dss-of.c @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2013 Texas Instruments + * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include <linux/device.h> +#include <linux/err.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/seq_file.h> + +#include <video/omapdss.h> + +struct device_node * +omapdss_of_get_next_port(const struct device_node *parent, + struct device_node *prev) +{ + struct device_node *port = NULL; + + if (!parent) + return NULL; + + if (!prev) { + struct device_node *ports; + /* + * It's the first call, we have to find a port subnode + * within this node or within an optional 'ports' node. + */ + ports = of_get_child_by_name(parent, "ports"); + if (ports) + parent = ports; + + port = of_get_child_by_name(parent, "port"); + + /* release the 'ports' node */ + of_node_put(ports); + } else { + struct device_node *ports; + + ports = of_get_parent(prev); + if (!ports) + return NULL; + + do { + port = of_get_next_child(ports, prev); + if (!port) { + of_node_put(ports); + return NULL; + } + prev = port; + } while (of_node_cmp(port->name, "port") != 0); + } + + return port; +} +EXPORT_SYMBOL_GPL(omapdss_of_get_next_port); + +struct device_node * +omapdss_of_get_next_endpoint(const struct device_node *parent, + struct device_node *prev) +{ + struct device_node *ep = NULL; + + if (!parent) + return NULL; + + do { + ep = of_get_next_child(parent, prev); + if (!ep) + return NULL; + prev = ep; + } while (of_node_cmp(ep->name, "endpoint") != 0); + + return ep; +} +EXPORT_SYMBOL_GPL(omapdss_of_get_next_endpoint); + +static struct device_node * +omapdss_of_get_remote_device_node(const struct device_node *node) +{ + struct device_node *np; + int i; + + np = of_parse_phandle(node, "remote-endpoint", 0); + + if (!np) + return NULL; + + np = of_get_next_parent(np); + + for (i = 0; i < 3 && np; ++i) { + struct property *prop; + + prop = of_find_property(np, "compatible", NULL); + + if (prop) + return np; + + np = of_get_next_parent(np); + } + + return NULL; +} + +struct device_node * +omapdss_of_get_first_endpoint(const struct device_node *parent) +{ + struct device_node *port, *ep; + + port = omapdss_of_get_next_port(parent, NULL); + + if (!port) + return NULL; + + ep = omapdss_of_get_next_endpoint(port, NULL); + + of_node_put(port); + + return ep; +} +EXPORT_SYMBOL_GPL(omapdss_of_get_first_endpoint); + +struct omap_dss_device * +omapdss_of_find_source_for_first_ep(struct device_node *node) +{ + struct device_node *ep; + struct device_node *src_node; + struct omap_dss_device *src; + + ep = omapdss_of_get_first_endpoint(node); + if (!ep) + return ERR_PTR(-EINVAL); + + src_node = omapdss_of_get_remote_device_node(ep); + + of_node_put(ep); + + if (!src_node) + return ERR_PTR(-EINVAL); + + src = omap_dss_find_output_by_node(src_node); + + of_node_put(src_node); + + if (!src) + return ERR_PTR(-EPROBE_DEFER); + + return src; +} +EXPORT_SYMBOL_GPL(omapdss_of_find_source_for_first_ep); diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 96e400c51001..825c019ddee7 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -23,6 +23,7 @@ #define DSS_SUBSYS_NAME "DSS" #include <linux/kernel.h> +#include <linux/module.h> #include <linux/io.h> #include <linux/export.h> #include <linux/err.h> @@ -33,6 +34,7 @@ #include <linux/pm_runtime.h> #include <linux/gfp.h> #include <linux/sizes.h> +#include <linux/of.h> #include <video/omapdss.h> @@ -772,6 +774,56 @@ static int __init dss_init_features(struct platform_device *pdev) return 0; } +static int __init dss_init_ports(struct platform_device *pdev) +{ + struct device_node *parent = pdev->dev.of_node; + struct device_node *port; + int r; + + if (parent == NULL) + return 0; + + port = omapdss_of_get_next_port(parent, NULL); + if (!port) { +#ifdef CONFIG_OMAP2_DSS_DPI + dpi_init_port(pdev, parent); +#endif + return 0; + } + + do { + u32 reg; + + r = of_property_read_u32(port, "reg", ®); + if (r) + reg = 0; + +#ifdef CONFIG_OMAP2_DSS_DPI + if (reg == 0) + dpi_init_port(pdev, port); +#endif + +#ifdef CONFIG_OMAP2_DSS_SDI + if (reg == 1) + sdi_init_port(pdev, port); +#endif + + } while ((port = omapdss_of_get_next_port(parent, port)) != NULL); + + return 0; +} + +static void dss_uninit_ports(void) +{ +#ifdef CONFIG_OMAP2_DSS_DPI + dpi_uninit_port(); +#endif + +#ifdef CONFIG_OMAP2_DSS_SDI + sdi_uninit_port(); +#endif +} + /* DSS HW IP initialisation */ static int __init omap_dsshw_probe(struct platform_device *pdev) { @@ -830,6 +882,8 @@ static int __init omap_dsshw_probe(struct platform_device *pdev) dss.lcd_clk_source[0] = OMAP_DSS_CLK_SRC_FCK; dss.lcd_clk_source[1] = OMAP_DSS_CLK_SRC_FCK; + dss_init_ports(pdev); + rev = dss_read_reg(DSS_REVISION); printk(KERN_INFO "OMAP DSS rev %d.%d\n", FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); @@ -849,6 +903,8 @@ err_setup_clocks: static int __exit omap_dsshw_remove(struct platform_device *pdev) { + dss_uninit_ports(); + pm_runtime_disable(&pdev->dev); dss_put_clocks(); @@ -886,12 +942,22 @@ static const struct dev_pm_ops dss_pm_ops = { .runtime_resume = dss_runtime_resume, }; +static const struct of_device_id dss_of_match[] = { + { .compatible = "ti,omap2-dss", }, + { .compatible = "ti,omap3-dss", }, + { .compatible = "ti,omap4-dss", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, dss_of_match); + static struct platform_driver omap_dsshw_driver = { .remove = __exit_p(omap_dsshw_remove), .driver = { .name = "omapdss_dss", .owner = THIS_MODULE, .pm = &dss_pm_ops, + .of_match_table = dss_of_match, }, }; diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 570f7ed2bcbc..918fec182424 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -250,6 +250,9 @@ bool dss_div_calc(unsigned long pck, unsigned long fck_min, int sdi_init_platform_driver(void) __init; void sdi_uninit_platform_driver(void) __exit; +int sdi_init_port(struct platform_device *pdev, struct device_node *port) __init; +void sdi_uninit_port(void) __exit; + /* DSI */ typedef bool (*dsi_pll_calc_func)(int regn, int regm, unsigned long fint, @@ -361,6 +364,9 @@ static inline bool dsi_pll_calc(struct platform_device *dsidev, int dpi_init_platform_driver(void) __init; void dpi_uninit_platform_driver(void) __exit; +int dpi_init_port(struct platform_device *pdev, struct device_node *port) __init; +void dpi_uninit_port(void) __exit; + /* DISPC */ int dispc_init_platform_driver(void) __init; void dispc_uninit_platform_driver(void) __exit; diff --git a/drivers/video/omap2/dss/hdmi4.c b/drivers/video/omap2/dss/hdmi4.c index 895c252ae0a8..f5f7944a1fd1 100644 --- a/drivers/video/omap2/dss/hdmi4.c +++ b/drivers/video/omap2/dss/hdmi4.c @@ -88,15 +88,11 @@ static int hdmi_init_regulator(void) if (hdmi.vdda_hdmi_dac_reg != NULL) return 0; - reg = devm_regulator_get(&hdmi.pdev->dev, "vdda_hdmi_dac"); - - /* DT HACK: try VDAC to make omapdss work for o4 sdp/panda */ - if (IS_ERR(reg)) - reg = devm_regulator_get(&hdmi.pdev->dev, "VDAC"); + reg = devm_regulator_get(&hdmi.pdev->dev, "vdda"); if (IS_ERR(reg)) { if (PTR_ERR(reg) != -EPROBE_DEFER) - DSSERR("can't get VDDA_HDMI_DAC regulator\n"); + DSSERR("can't get VDDA regulator\n"); return PTR_ERR(reg); } @@ -680,6 +676,11 @@ static const struct dev_pm_ops hdmi_pm_ops = { .runtime_resume = hdmi_runtime_resume, }; +static const struct of_device_id hdmi_of_match[] = { + { .compatible = "ti,omap4-hdmi", }, + {}, +}; + static struct platform_driver omapdss_hdmihw_driver = { .probe = omapdss_hdmihw_probe, .remove = __exit_p(omapdss_hdmihw_remove), @@ -687,6 +688,7 @@ static struct platform_driver omapdss_hdmihw_driver = { .name = "omapdss_hdmi", .owner = THIS_MODULE, .pm = &hdmi_pm_ops, + .of_match_table = hdmi_of_match, }, }; diff --git a/drivers/video/omap2/dss/hdmi_wp.c b/drivers/video/omap2/dss/hdmi_wp.c index cd620c6e43a0..f5f4ccf50d90 100644 --- a/drivers/video/omap2/dss/hdmi_wp.c +++ b/drivers/video/omap2/dss/hdmi_wp.c @@ -171,6 +171,8 @@ void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt, video_fmt->packing_mode = HDMI_PACK_10b_RGB_YUV444; video_fmt->y_res = param->timings.y_res; video_fmt->x_res = param->timings.x_res; + if (param->timings.interlace) + video_fmt->y_res /= 2; timings->hbp = param->timings.hbp; timings->hfp = param->timings.hfp; diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c index b679e33adf2d..911dcc9173a6 100644 --- a/drivers/video/omap2/dss/sdi.c +++ b/drivers/video/omap2/dss/sdi.c @@ -26,6 +26,7 @@ #include <linux/export.h> #include <linux/platform_device.h> #include <linux/string.h> +#include <linux/of.h> #include <video/omapdss.h> #include "dss.h" @@ -41,6 +42,8 @@ static struct { int datapairs; struct omap_dss_device output; + + bool port_initialized; } sdi; struct sdi_clk_calc_ctx { @@ -386,3 +389,45 @@ void __exit sdi_uninit_platform_driver(void) { platform_driver_unregister(&omap_sdi_driver); } + +int __init sdi_init_port(struct platform_device *pdev, struct device_node *port) +{ + struct device_node *ep; + u32 datapairs; + int r; + + ep = omapdss_of_get_next_endpoint(port, NULL); + if (!ep) + return 0; + + r = of_property_read_u32(ep, "datapairs", &datapairs); + if (r) { + DSSERR("failed to parse datapairs\n"); + goto err_datapairs; + } + + sdi.datapairs = datapairs; + + of_node_put(ep); + + sdi.pdev = pdev; + + sdi_init_output(pdev); + + sdi.port_initialized = true; + + return 0; + +err_datapairs: + of_node_put(ep); + + return r; +} + +void __exit sdi_uninit_port(void) +{ + if (!sdi.port_initialized) + return; + + sdi_uninit_output(sdi.pdev); +} diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c index 59ade34bd536..21d81113962b 100644 --- a/drivers/video/omap2/dss/venc.c +++ b/drivers/video/omap2/dss/venc.c @@ -34,6 +34,7 @@ #include <linux/platform_device.h> #include <linux/regulator/consumer.h> #include <linux/pm_runtime.h> +#include <linux/of.h> #include <video/omapdss.h> @@ -636,7 +637,10 @@ static int venc_init_regulator(void) if (venc.vdda_dac_reg != NULL) return 0; - vdda_dac = devm_regulator_get(&venc.pdev->dev, "vdda_dac"); + if (venc.pdev->dev.of_node) + vdda_dac = devm_regulator_get(&venc.pdev->dev, "vdda"); + else + vdda_dac = devm_regulator_get(&venc.pdev->dev, "vdda_dac"); if (IS_ERR(vdda_dac)) { if (PTR_ERR(vdda_dac) != -EPROBE_DEFER) @@ -805,6 +809,48 @@ static void __exit venc_uninit_output(struct platform_device *pdev) omapdss_unregister_output(out); } +static int venc_probe_of(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct device_node *ep; + u32 channels; + int r; + + ep = omapdss_of_get_first_endpoint(node); + if (!ep) + return 0; + + venc.invert_polarity = of_property_read_bool(ep, "ti,invert-polarity"); + + r = of_property_read_u32(ep, "ti,channels", &channels); + if (r) { + dev_err(&pdev->dev, + "failed to read property 'ti,channels': %d\n", r); + goto err; + } + + switch (channels) { + case 1: + venc.type = OMAP_DSS_VENC_TYPE_COMPOSITE; + break; + case 2: + venc.type = OMAP_DSS_VENC_TYPE_SVIDEO; + break; + default: + dev_err(&pdev->dev, "bad channel propert '%d'\n", channels); + r = -EINVAL; + goto err; + } + + of_node_put(ep); + + return 0; +err: + of_node_put(ep); + + return 0; +} + /* VENC HW IP initialisation */ static int omap_venchw_probe(struct platform_device *pdev) { @@ -846,12 +892,21 @@ static int omap_venchw_probe(struct platform_device *pdev) venc_runtime_put(); + if (pdev->dev.of_node) { + r = venc_probe_of(pdev); + if (r) { + DSSERR("Invalid DT data\n"); + goto err_probe_of; + } + } + dss_debugfs_create_file("venc", venc_dump_regs); venc_init_output(pdev); return 0; +err_probe_of: err_runtime_get: pm_runtime_disable(&pdev->dev); return r; @@ -895,6 +950,14 @@ static const struct dev_pm_ops venc_pm_ops = { .runtime_resume = venc_runtime_resume, }; + +static const struct of_device_id venc_of_match[] = { + { .compatible = "ti,omap2-venc", }, + { .compatible = "ti,omap3-venc", }, + { .compatible = "ti,omap4-venc", }, + {}, +}; + static struct platform_driver omap_venchw_driver = { .probe = omap_venchw_probe, .remove = __exit_p(omap_venchw_remove), @@ -902,6 +965,7 @@ static struct platform_driver omap_venchw_driver = { .name = "omapdss_venc", .owner = THIS_MODULE, .pm = &venc_pm_ops, + .of_match_table = venc_of_match, }, }; diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index 8d02f164c8c6..ec2d132c782d 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -2417,6 +2417,55 @@ static int omapfb_init_connections(struct omapfb2_device *fbdev, return 0; } +static struct omap_dss_device * +omapfb_find_default_display(struct omapfb2_device *fbdev) +{ + const char *def_name; + int i; + + /* + * Search with the display name from the user or the board file, + * comparing to display names and aliases + */ + + def_name = omapdss_get_default_display_name(); + + if (def_name) { + for (i = 0; i < fbdev->num_displays; ++i) { + struct omap_dss_device *dssdev; + + dssdev = fbdev->displays[i].dssdev; + + if (dssdev->name && strcmp(def_name, dssdev->name) == 0) + return dssdev; + + if (strcmp(def_name, dssdev->alias) == 0) + return dssdev; + } + + /* def_name given but not found */ + return NULL; + } + + /* then look for DT alias display0 */ + for (i = 0; i < fbdev->num_displays; ++i) { + struct omap_dss_device *dssdev; + int id; + + dssdev = fbdev->displays[i].dssdev; + + if (dssdev->dev->of_node == NULL) + continue; + + id = of_alias_get_id(dssdev->dev->of_node, "display"); + if (id == 0) + return dssdev; + } + + /* return the first display we have in the list */ + return fbdev->displays[0].dssdev; +} + static int omapfb_probe(struct platform_device *pdev) { struct omapfb2_device *fbdev = NULL; @@ -2494,23 +2543,7 @@ static int omapfb_probe(struct platform_device *pdev) for (i = 0; i < fbdev->num_managers; i++) fbdev->managers[i] = omap_dss_get_overlay_manager(i); - def_display = NULL; - - for (i = 0; i < fbdev->num_displays; ++i) { - struct omap_dss_device *dssdev; - const char *def_name; - - def_name = omapdss_get_default_display_name(); - - dssdev = fbdev->displays[i].dssdev; - - if (def_name == NULL || - (dssdev->name && strcmp(def_name, dssdev->name) == 0)) { - def_display = dssdev; - break; - } - } - + def_display = omapfb_find_default_display(fbdev); if (def_display == NULL) { dev_err(fbdev->dev, "failed to find default display\n"); r = -EPROBE_DEFER; diff --git a/include/video/omapdss.h b/include/video/omapdss.h index 24f3a57022b8..6adb44534606 100644 --- a/include/video/omapdss.h +++ b/include/video/omapdss.h @@ -1018,4 +1018,18 @@ static inline bool omapdss_device_is_enabled(struct omap_dss_device *dssdev) return dssdev->state == OMAP_DSS_DISPLAY_ACTIVE; } +struct device_node * +omapdss_of_get_next_port(const struct device_node *parent, + struct device_node *prev); + +struct device_node * +omapdss_of_get_next_endpoint(const struct device_node *parent, + struct device_node *prev); + +struct device_node * +omapdss_of_get_first_endpoint(const struct device_node *parent); + +struct omap_dss_device * +omapdss_of_find_source_for_first_ep(struct device_node *node); + #endif |