diff --git a/Documentation/devicetree/bindings/video/adi,adv7511.txt b/Documentation/devicetree/bindings/video/adi,adv7511.txt new file mode 100644 index 000000000000..96c25ee01501 --- /dev/null +++ b/Documentation/devicetree/bindings/video/adi,adv7511.txt @@ -0,0 +1,88 @@ +Analog Device ADV7511(W)/13 HDMI Encoders +----------------------------------------- + +The ADV7511, ADV7511W and ADV7513 are HDMI audio and video transmitters +compatible with HDMI 1.4 and DVI 1.0. They support color space conversion, +S/PDIF, CEC and HDCP. + +Required properties: + +- compatible: Should be one of "adi,adv7511", "adi,adv7511w" or "adi,adv7513" +- reg: I2C slave address + +The ADV7511 supports a large number of input data formats that differ by their +color depth, color format, clock mode, bit justification and random +arrangement of components on the data bus. The combination of the following +properties describe the input and map directly to the video input tables of the +ADV7511 datasheet that document all the supported combinations. + +- adi,input-depth: Number of bits per color component at the input (8, 10 or + 12). +- adi,input-colorspace: The input color space, one of "rgb", "yuv422" or + "yuv444". +- adi,input-clock: The input clock type, one of "1x" (one clock cycle per + pixel), "2x" (two clock cycles per pixel), "ddr" (one clock cycle per pixel, + data driven on both edges). + +The following input format properties are required except in "rgb 1x" and +"yuv444 1x" modes, in which case they must not be specified. + +- adi,input-style: The input components arrangement variant (1, 2 or 3), as + listed in the input format tables in the datasheet. +- adi,input-justification: The input bit justification ("left", "evenly", + "right"). + +Optional properties: + +- interrupts: Specifier for the ADV7511 interrupt +- pd-gpios: Specifier for the GPIO connected to the power down signal + +- adi,clock-delay: Video data clock delay relative to the pixel clock, in ps + (-1200 ps .. 1600 ps). Defaults to no delay. +- adi,embedded-sync: The input uses synchronization signals embedded in the + data stream (similar to BT.656). Defaults to separate H/V synchronization + signals. + +Required nodes: + +The ADV7511 has two video ports. Their connections are modelled using the OF +graph bindings specified in Documentation/devicetree/bindings/graph.txt. + +- Video port 0 for the RGB or YUV input +- Video port 1 for the HDMI output + + +Example +------- + + adv7511w: hdmi@39 { + compatible = "adi,adv7511w"; + reg = <39>; + interrupt-parent = <&gpio3>; + interrupts = <29 IRQ_TYPE_EDGE_FALLING>; + + adi,input-depth = <8>; + adi,input-colorspace = "rgb"; + adi,input-clock = "1x"; + adi,input-style = <1>; + adi,input-justification = "evenly"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + adv7511w_in: endpoint { + remote-endpoint = <&dpi_out>; + }; + }; + + port@1 { + reg = <1>; + adv7511_out: endpoint { + remote-endpoint = <&hdmi_connector_in>; + }; + }; + }; + }; diff --git a/arch/arm/boot/dts/r8a7779-marzen.dts b/arch/arm/boot/dts/r8a7779-marzen.dts index c160404e4d40..765978fe430b 100644 --- a/arch/arm/boot/dts/r8a7779-marzen.dts +++ b/arch/arm/boot/dts/r8a7779-marzen.dts @@ -68,6 +68,78 @@ gpios = <&gpio4 31 GPIO_ACTIVE_HIGH>; }; }; + + vga-encoder { + compatible = "adi,adv7123"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + vga_enc_in: endpoint { + remote-endpoint = <&du_out_rgb0>; + }; + }; + port@1 { + reg = <1>; + vga_enc_out: endpoint { + remote-endpoint = <&vga_in>; + }; + }; + }; + }; + + vga { + compatible = "vga-connector"; + + port { + vga_in: endpoint { + remote-endpoint = <&vga_enc_out>; + }; + }; + }; + + lvds-encoder { + compatible = "thine,thc63lvdm83d"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + lvds_enc_in: endpoint { + remote-endpoint = <&du_out_rgb1>; + }; + }; + port@1 { + reg = <1>; + lvds_connector: endpoint { + }; + }; + }; + }; +}; + +&du { + pinctrl-0 = <&du_pins>; + pinctrl-names = "default"; + status = "okay"; + + ports { + port@0 { + endpoint { + remote-endpoint = <&vga_enc_in>; + }; + }; + port@1 { + endpoint { + remote-endpoint = <&lvds_enc_in>; + }; + }; + }; }; &irqpin0 { @@ -83,6 +155,17 @@ }; &pfc { + du_pins: du { + du0 { + renesas,groups = "du0_rgb888", "du0_sync_1", "du0_clk_out_0"; + renesas,function = "du0"; + }; + du1 { + renesas,groups = "du1_rgb666", "du1_sync_1", "du1_clk_out"; + renesas,function = "du1"; + }; + }; + lan0_pins: lan0 { intc { renesas,groups = "intc_irq1_b"; diff --git a/arch/arm/boot/dts/r8a7779.dtsi b/arch/arm/boot/dts/r8a7779.dtsi index 7cfba9aa1b41..fda814ed191d 100644 --- a/arch/arm/boot/dts/r8a7779.dtsi +++ b/arch/arm/boot/dts/r8a7779.dtsi @@ -379,6 +379,30 @@ status = "disabled"; }; + du: display@fff80000 { + compatible = "renesas,du-r8a7779"; + reg = <0 0xfff80000 0 0x40000>; + interrupts = <0 31 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp1_clks R8A7779_CLK_DU>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + du_out_rgb0: endpoint { + }; + }; + port@1 { + reg = <1>; + du_out_rgb1: endpoint { + }; + }; + }; + }; + clocks { #address-cells = <1>; #size-cells = <1>; diff --git a/arch/arm/boot/dts/r8a7790-lager.dts b/arch/arm/boot/dts/r8a7790-lager.dts index 69098b906b39..5237d463ae1d 100644 --- a/arch/arm/boot/dts/r8a7790-lager.dts +++ b/arch/arm/boot/dts/r8a7790-lager.dts @@ -144,6 +144,56 @@ states = <3300000 1 1800000 0>; }; + + vga-encoder { + compatible = "adi,adv7123"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + adv7123_in: endpoint { + remote-endpoint = <&du_out_rgb>; + }; + }; + port@1 { + reg = <1>; + adv7123_out: endpoint { + remote-endpoint = <&vga_in>; + }; + }; + }; + }; + + vga { + compatible = "vga-connector"; + + port { + vga_in: endpoint { + remote-endpoint = <&adv7123_out>; + }; + }; + }; +}; + +&du { + pinctrl-0 = <&du_pins>; + pinctrl-names = "default"; + status = "okay"; + + ports { + port@0 { + endpoint { + remote-endpoint = <&adv7123_in>; + }; + }; + port@2 { + lvds_connector: endpoint { + }; + }; + }; }; &extal_clk { @@ -151,9 +201,6 @@ }; &pfc { - pinctrl-0 = <&du_pins>; - pinctrl-names = "default"; - du_pins: du { renesas,groups = "du_rgb666", "du_sync_1", "du_clk_out_0"; renesas,function = "du"; diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi index d0e17733dc1a..b7c59b7b06b0 100644 --- a/arch/arm/boot/dts/r8a7790.dtsi +++ b/arch/arm/boot/dts/r8a7790.dtsi @@ -600,6 +600,96 @@ status = "disabled"; }; + vsp1@fe920000 { + compatible = "renesas,vsp1"; + reg = <0 0xfe920000 0 0x8000>; + interrupts = <0 266 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp1_clks R8A7790_CLK_VSP1_R>; + + renesas,has-sru; + renesas,#rpf = <5>; + renesas,#uds = <1>; + renesas,#wpf = <4>; + }; + + vsp1@fe928000 { + compatible = "renesas,vsp1"; + reg = <0 0xfe928000 0 0x8000>; + interrupts = <0 267 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp1_clks R8A7790_CLK_VSP1_S>; + + renesas,has-lut; + renesas,has-sru; + renesas,#rpf = <5>; + renesas,#uds = <3>; + renesas,#wpf = <4>; + }; + + vsp1@fe930000 { + compatible = "renesas,vsp1"; + reg = <0 0xfe930000 0 0x8000>; + interrupts = <0 246 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp1_clks R8A7790_CLK_VSP1_DU0>; + + renesas,has-lif; + renesas,has-lut; + renesas,#rpf = <4>; + renesas,#uds = <1>; + renesas,#wpf = <4>; + }; + + vsp1@fe938000 { + compatible = "renesas,vsp1"; + reg = <0 0xfe938000 0 0x8000>; + interrupts = <0 247 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp1_clks R8A7790_CLK_VSP1_DU1>; + + renesas,has-lif; + renesas,has-lut; + renesas,#rpf = <4>; + renesas,#uds = <1>; + renesas,#wpf = <4>; + }; + + du: display@feb00000 { + compatible = "renesas,du-r8a7790"; + reg = <0 0xfeb00000 0 0x70000>, + <0 0xfeb90000 0 0x1c>, + <0 0xfeb94000 0 0x1c>; + reg-names = "du", "lvds.0", "lvds.1"; + interrupts = <0 256 IRQ_TYPE_LEVEL_HIGH>, + <0 268 IRQ_TYPE_LEVEL_HIGH>, + <0 269 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp7_clks R8A7790_CLK_DU0>, + <&mstp7_clks R8A7790_CLK_DU1>, + <&mstp7_clks R8A7790_CLK_DU2>, + <&mstp7_clks R8A7790_CLK_LVDS0>, + <&mstp7_clks R8A7790_CLK_LVDS1>; + clock-names = "du.0", "du.1", "du.2", "lvds.0", "lvds.1"; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + du_out_rgb: endpoint { + }; + }; + port@1 { + reg = <1>; + du_out_lvds0: endpoint { + }; + }; + port@2 { + reg = <2>; + du_out_lvds1: endpoint { + }; + }; + }; + }; + clocks { #address-cells = <2>; #size-cells = <2>; diff --git a/arch/arm/boot/dts/r8a7791-koelsch.dts b/arch/arm/boot/dts/r8a7791-koelsch.dts index 07550e775e80..4f4e56e5de3d 100644 --- a/arch/arm/boot/dts/r8a7791-koelsch.dts +++ b/arch/arm/boot/dts/r8a7791-koelsch.dts @@ -211,14 +211,24 @@ }; }; +&du { + pinctrl-0 = <&du_pins>; + pinctrl-names = "default"; + status = "okay"; + + ports { + port@1 { + lvds_connector: endpoint { + }; + }; + }; +}; + &extal_clk { clock-frequency = <20000000>; }; &pfc { - pinctrl-0 = <&du_pins>; - pinctrl-names = "default"; - i2c2_pins: i2c2 { renesas,groups = "i2c2"; renesas,function = "i2c2"; diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi index e06c11fa8698..e4a7170f368b 100644 --- a/arch/arm/boot/dts/r8a7791.dtsi +++ b/arch/arm/boot/dts/r8a7791.dtsi @@ -637,6 +637,75 @@ status = "disabled"; }; + vsp1@fe928000 { + compatible = "renesas,vsp1"; + reg = <0 0xfe928000 0 0x8000>; + interrupts = <0 267 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp1_clks R8A7791_CLK_VSP1_S>; + + renesas,has-lut; + renesas,has-sru; + renesas,#rpf = <5>; + renesas,#uds = <3>; + renesas,#wpf = <4>; + }; + + vsp1@fe930000 { + compatible = "renesas,vsp1"; + reg = <0 0xfe930000 0 0x8000>; + interrupts = <0 246 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp1_clks R8A7791_CLK_VSP1_DU0>; + + renesas,has-lif; + renesas,has-lut; + renesas,#rpf = <4>; + renesas,#uds = <1>; + renesas,#wpf = <4>; + }; + + vsp1@fe938000 { + compatible = "renesas,vsp1"; + reg = <0 0xfe938000 0 0x8000>; + interrupts = <0 247 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp1_clks R8A7791_CLK_VSP1_DU1>; + + renesas,has-lif; + renesas,has-lut; + renesas,#rpf = <4>; + renesas,#uds = <1>; + renesas,#wpf = <4>; + }; + + du: display@feb00000 { + compatible = "renesas,du-r8a7791"; + reg = <0 0xfeb00000 0 0x40000>, + <0 0xfeb90000 0 0x1c>; + reg-names = "du", "lvds.0"; + interrupts = <0 256 IRQ_TYPE_LEVEL_HIGH>, + <0 268 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp7_clks R8A7791_CLK_DU0>, + <&mstp7_clks R8A7791_CLK_DU1>, + <&mstp7_clks R8A7791_CLK_LVDS0>; + clock-names = "du.0", "du.1", "lvds.0"; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + du_out_rgb: endpoint { + }; + }; + port@1 { + reg = <1>; + du_out_lvds0: endpoint { + }; + }; + }; + }; + clocks { #address-cells = <2>; #size-cells = <2>; diff --git a/arch/arm/boot/dts/r8a77xx-aa104xd12-panel.dtsi b/arch/arm/boot/dts/r8a77xx-aa104xd12-panel.dtsi new file mode 100644 index 000000000000..65cb50f0c29f --- /dev/null +++ b/arch/arm/boot/dts/r8a77xx-aa104xd12-panel.dtsi @@ -0,0 +1,41 @@ +/* + * Common file for the AA104XD12 panel connected to Renesas R-Car boards + * + * Copyright (C) 2014 Renesas Electronics Corp. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +/ { + panel { + compatible = "mitsubishi,aa104xd12", "panel-dpi"; + + width-mm = <210>; + height-mm = <158>; + + panel-timing { + /* 1024x768 @65Hz */ + clock-frequency = <65000000>; + hactive = <1024>; + vactive = <768>; + hsync-len = <136>; + hfront-porch = <20>; + hback-porch = <160>; + vfront-porch = <3>; + vback-porch = <29>; + vsync-len = <6>; + }; + + port { + panel_in: endpoint { + remote-endpoint = <&lvds_connector>; + }; + }; + }; +}; + +&lvds_connector { + remote-endpoint = <&panel_in>; +}; diff --git a/arch/arm/mach-shmobile/board-ape6evm-reference.c b/arch/arm/mach-shmobile/board-ape6evm-reference.c index a6503d8c77de..004ed92ee598 100644 --- a/arch/arm/mach-shmobile/board-ape6evm-reference.c +++ b/arch/arm/mach-shmobile/board-ape6evm-reference.c @@ -12,10 +12,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include diff --git a/arch/arm/mach-shmobile/board-ape6evm.c b/arch/arm/mach-shmobile/board-ape6evm.c index b222f68d55b7..66f67816a844 100644 --- a/arch/arm/mach-shmobile/board-ape6evm.c +++ b/arch/arm/mach-shmobile/board-ape6evm.c @@ -12,10 +12,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include diff --git a/arch/arm/mach-shmobile/board-armadillo800eva.c b/arch/arm/mach-shmobile/board-armadillo800eva.c index e70983534403..0e912aff53de 100644 --- a/arch/arm/mach-shmobile/board-armadillo800eva.c +++ b/arch/arm/mach-shmobile/board-armadillo800eva.c @@ -12,11 +12,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #include diff --git a/arch/arm/mach-shmobile/board-bockw-reference.c b/arch/arm/mach-shmobile/board-bockw-reference.c index 79c47847f200..d649ade4a202 100644 --- a/arch/arm/mach-shmobile/board-bockw-reference.c +++ b/arch/arm/mach-shmobile/board-bockw-reference.c @@ -12,10 +12,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include diff --git a/arch/arm/mach-shmobile/board-bockw.c b/arch/arm/mach-shmobile/board-bockw.c index 1cf2c75dacfb..f27b5a833bf0 100644 --- a/arch/arm/mach-shmobile/board-bockw.c +++ b/arch/arm/mach-shmobile/board-bockw.c @@ -13,10 +13,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include diff --git a/arch/arm/mach-shmobile/board-koelsch-reference.c b/arch/arm/mach-shmobile/board-koelsch-reference.c index 46aa540133d6..451ba624ce6e 100644 --- a/arch/arm/mach-shmobile/board-koelsch-reference.c +++ b/arch/arm/mach-shmobile/board-koelsch-reference.c @@ -13,93 +13,17 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include #include #include -#include #include -#include "clock.h" #include "common.h" -#include "irqs.h" #include "r8a7791.h" #include "rcar-gen2.h" -/* DU */ -static struct rcar_du_encoder_data koelsch_du_encoders[] = { - { - .type = RCAR_DU_ENCODER_NONE, - .output = RCAR_DU_OUTPUT_LVDS0, - .connector.lvds.panel = { - .width_mm = 210, - .height_mm = 158, - .mode = { - .pixelclock = 65000000, - .hactive = 1024, - .hfront_porch = 20, - .hback_porch = 160, - .hsync_len = 136, - .vactive = 768, - .vfront_porch = 3, - .vback_porch = 29, - .vsync_len = 6, - }, - }, - }, -}; - -static struct rcar_du_platform_data koelsch_du_pdata = { - .encoders = koelsch_du_encoders, - .num_encoders = ARRAY_SIZE(koelsch_du_encoders), -}; - -static const struct resource du_resources[] __initconst = { - DEFINE_RES_MEM(0xfeb00000, 0x40000), - DEFINE_RES_MEM_NAMED(0xfeb90000, 0x1c, "lvds.0"), - DEFINE_RES_IRQ(gic_spi(256)), - DEFINE_RES_IRQ(gic_spi(268)), -}; - -static void __init koelsch_add_du_device(void) -{ - struct platform_device_info info = { - .name = "rcar-du-r8a7791", - .id = -1, - .res = du_resources, - .num_res = ARRAY_SIZE(du_resources), - .data = &koelsch_du_pdata, - .size_data = sizeof(koelsch_du_pdata), - .dma_mask = DMA_BIT_MASK(32), - }; - - platform_device_register_full(&info); -} - -/* - * This is a really crude hack to provide clkdev support to platform - * devices until they get moved to DT. - */ -static const struct clk_name clk_names[] __initconst = { - { "du0", "du.0", "rcar-du-r8a7791" }, - { "du1", "du.1", "rcar-du-r8a7791" }, - { "lvds0", "lvds.0", "rcar-du-r8a7791" }, -}; - -static void __init koelsch_add_standard_devices(void) -{ - shmobile_clk_workaround(clk_names, ARRAY_SIZE(clk_names), false); - of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); - - koelsch_add_du_device(); -} - static const char * const koelsch_boards_compat_dt[] __initconst = { "renesas,koelsch", "renesas,koelsch-reference", @@ -110,7 +34,6 @@ DT_MACHINE_START(KOELSCH_DT, "koelsch") .smp = smp_ops(r8a7791_smp_ops), .init_early = shmobile_init_delay, .init_time = rcar_gen2_timer_init, - .init_machine = koelsch_add_standard_devices, .init_late = shmobile_init_late, .reserve = rcar_gen2_reserve, .dt_compat = koelsch_boards_compat_dt, diff --git a/arch/arm/mach-shmobile/board-koelsch.c b/arch/arm/mach-shmobile/board-koelsch.c index 7111b5c1d67b..3a6a2766dc2b 100644 --- a/arch/arm/mach-shmobile/board-koelsch.c +++ b/arch/arm/mach-shmobile/board-koelsch.c @@ -14,10 +14,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include diff --git a/arch/arm/mach-shmobile/board-kzm9g-reference.c b/arch/arm/mach-shmobile/board-kzm9g-reference.c index d9cdf9a97e23..f2ef759b6e96 100644 --- a/arch/arm/mach-shmobile/board-kzm9g-reference.c +++ b/arch/arm/mach-shmobile/board-kzm9g-reference.c @@ -14,10 +14,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include diff --git a/arch/arm/mach-shmobile/board-kzm9g.c b/arch/arm/mach-shmobile/board-kzm9g.c index 77e36fa0b142..7c9b63bdde9f 100644 --- a/arch/arm/mach-shmobile/board-kzm9g.c +++ b/arch/arm/mach-shmobile/board-kzm9g.c @@ -11,10 +11,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include diff --git a/arch/arm/mach-shmobile/board-lager-reference.c b/arch/arm/mach-shmobile/board-lager-reference.c index bc4b48357dde..fa06bdba61df 100644 --- a/arch/arm/mach-shmobile/board-lager-reference.c +++ b/arch/arm/mach-shmobile/board-lager-reference.c @@ -12,100 +12,17 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include #include #include -#include #include -#include "clock.h" #include "common.h" -#include "irqs.h" #include "r8a7790.h" #include "rcar-gen2.h" -/* DU */ -static struct rcar_du_encoder_data lager_du_encoders[] = { - { - .type = RCAR_DU_ENCODER_VGA, - .output = RCAR_DU_OUTPUT_DPAD0, - }, { - .type = RCAR_DU_ENCODER_NONE, - .output = RCAR_DU_OUTPUT_LVDS1, - .connector.lvds.panel = { - .width_mm = 210, - .height_mm = 158, - .mode = { - .pixelclock = 65000000, - .hactive = 1024, - .hfront_porch = 20, - .hback_porch = 160, - .hsync_len = 136, - .vactive = 768, - .vfront_porch = 3, - .vback_porch = 29, - .vsync_len = 6, - }, - }, - }, -}; - -static struct rcar_du_platform_data lager_du_pdata = { - .encoders = lager_du_encoders, - .num_encoders = ARRAY_SIZE(lager_du_encoders), -}; - -static const struct resource du_resources[] __initconst = { - DEFINE_RES_MEM(0xfeb00000, 0x70000), - DEFINE_RES_MEM_NAMED(0xfeb90000, 0x1c, "lvds.0"), - DEFINE_RES_MEM_NAMED(0xfeb94000, 0x1c, "lvds.1"), - DEFINE_RES_IRQ(gic_spi(256)), - DEFINE_RES_IRQ(gic_spi(268)), - DEFINE_RES_IRQ(gic_spi(269)), -}; - -static void __init lager_add_du_device(void) -{ - struct platform_device_info info = { - .name = "rcar-du-r8a7790", - .id = -1, - .res = du_resources, - .num_res = ARRAY_SIZE(du_resources), - .data = &lager_du_pdata, - .size_data = sizeof(lager_du_pdata), - .dma_mask = DMA_BIT_MASK(32), - }; - - platform_device_register_full(&info); -} - -/* - * This is a really crude hack to provide clkdev support to platform - * devices until they get moved to DT. - */ -static const struct clk_name clk_names[] __initconst = { - { "du0", "du.0", "rcar-du-r8a7790" }, - { "du1", "du.1", "rcar-du-r8a7790" }, - { "du2", "du.2", "rcar-du-r8a7790" }, - { "lvds0", "lvds.0", "rcar-du-r8a7790" }, - { "lvds1", "lvds.1", "rcar-du-r8a7790" }, -}; - -static void __init lager_add_standard_devices(void) -{ - shmobile_clk_workaround(clk_names, ARRAY_SIZE(clk_names), false); - of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); - - lager_add_du_device(); -} - static const char *lager_boards_compat_dt[] __initdata = { "renesas,lager", "renesas,lager-reference", @@ -116,7 +33,6 @@ DT_MACHINE_START(LAGER_DT, "lager") .smp = smp_ops(r8a7790_smp_ops), .init_early = shmobile_init_delay, .init_time = rcar_gen2_timer_init, - .init_machine = lager_add_standard_devices, .init_late = shmobile_init_late, .reserve = rcar_gen2_reserve, .dt_compat = lager_boards_compat_dt, diff --git a/arch/arm/mach-shmobile/board-lager.c b/arch/arm/mach-shmobile/board-lager.c index 571327b1c942..b47262afb240 100644 --- a/arch/arm/mach-shmobile/board-lager.c +++ b/arch/arm/mach-shmobile/board-lager.c @@ -13,10 +13,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c index ca5d34b92aa7..ed1087031c5d 100644 --- a/arch/arm/mach-shmobile/board-mackerel.c +++ b/arch/arm/mach-shmobile/board-mackerel.c @@ -16,10 +16,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include diff --git a/arch/arm/mach-shmobile/board-marzen-reference.c b/arch/arm/mach-shmobile/board-marzen-reference.c index 38d9cdd26587..f0757bbaff87 100644 --- a/arch/arm/mach-shmobile/board-marzen-reference.c +++ b/arch/arm/mach-shmobile/board-marzen-reference.c @@ -13,10 +13,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include diff --git a/arch/arm/mach-shmobile/board-marzen.c b/arch/arm/mach-shmobile/board-marzen.c index ce33d7825c49..994dc7d86ae2 100644 --- a/arch/arm/mach-shmobile/board-marzen.c +++ b/arch/arm/mach-shmobile/board-marzen.c @@ -13,10 +13,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include diff --git a/arch/arm/mach-shmobile/clock-r8a73a4.c b/arch/arm/mach-shmobile/clock-r8a73a4.c index c2330ea1802c..1cf44dc6d718 100644 --- a/arch/arm/mach-shmobile/clock-r8a73a4.c +++ b/arch/arm/mach-shmobile/clock-r8a73a4.c @@ -12,10 +12,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include diff --git a/arch/arm/mach-shmobile/clock-r8a7740.c b/arch/arm/mach-shmobile/clock-r8a7740.c index 0794f0426e70..969e85dad09b 100644 --- a/arch/arm/mach-shmobile/clock-r8a7740.c +++ b/arch/arm/mach-shmobile/clock-r8a7740.c @@ -12,10 +12,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include diff --git a/arch/arm/mach-shmobile/clock-r8a7778.c b/arch/arm/mach-shmobile/clock-r8a7778.c index 67980a08a601..e8510c35558c 100644 --- a/arch/arm/mach-shmobile/clock-r8a7778.c +++ b/arch/arm/mach-shmobile/clock-r8a7778.c @@ -17,10 +17,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* diff --git a/arch/arm/mach-shmobile/clock-r8a7779.c b/arch/arm/mach-shmobile/clock-r8a7779.c index c51f9db3f66f..fa8ab2cc9187 100644 --- a/arch/arm/mach-shmobile/clock-r8a7779.c +++ b/arch/arm/mach-shmobile/clock-r8a7779.c @@ -12,10 +12,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include diff --git a/arch/arm/mach-shmobile/clock-r8a7790.c b/arch/arm/mach-shmobile/clock-r8a7790.c index 126ddafad526..c395ff194254 100644 --- a/arch/arm/mach-shmobile/clock-r8a7790.c +++ b/arch/arm/mach-shmobile/clock-r8a7790.c @@ -12,10 +12,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include diff --git a/arch/arm/mach-shmobile/clock-r8a7791.c b/arch/arm/mach-shmobile/clock-r8a7791.c index 453b23129cfa..82143ca3bae9 100644 --- a/arch/arm/mach-shmobile/clock-r8a7791.c +++ b/arch/arm/mach-shmobile/clock-r8a7791.c @@ -13,10 +13,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c index 7071676145c4..3bc92f46060e 100644 --- a/arch/arm/mach-shmobile/clock-sh7372.c +++ b/arch/arm/mach-shmobile/clock-sh7372.c @@ -11,10 +11,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include diff --git a/arch/arm/mach-shmobile/clock-sh73a0.c b/arch/arm/mach-shmobile/clock-sh73a0.c index 02a6f45a0b9e..6b4c1f313cc9 100644 --- a/arch/arm/mach-shmobile/clock-sh73a0.c +++ b/arch/arm/mach-shmobile/clock-sh73a0.c @@ -11,10 +11,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include diff --git a/arch/arm/mach-shmobile/clock.c b/arch/arm/mach-shmobile/clock.c index 806f94038cc4..1f81ad747153 100644 --- a/arch/arm/mach-shmobile/clock.c +++ b/arch/arm/mach-shmobile/clock.c @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #include #include diff --git a/arch/arm/mach-shmobile/console.c b/arch/arm/mach-shmobile/console.c index f2e79f2376e1..e329ccbd0a67 100644 --- a/arch/arm/mach-shmobile/console.c +++ b/arch/arm/mach-shmobile/console.c @@ -11,10 +11,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include diff --git a/arch/arm/mach-shmobile/headsmp-scu.S b/arch/arm/mach-shmobile/headsmp-scu.S index f45dde701d7b..69df8bfac167 100644 --- a/arch/arm/mach-shmobile/headsmp-scu.S +++ b/arch/arm/mach-shmobile/headsmp-scu.S @@ -12,11 +12,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA */ #include diff --git a/arch/arm/mach-shmobile/intc-sh7372.c b/arch/arm/mach-shmobile/intc-sh7372.c index e2af00b1bd9d..1ccf49cb485f 100644 --- a/arch/arm/mach-shmobile/intc-sh7372.c +++ b/arch/arm/mach-shmobile/intc-sh7372.c @@ -11,10 +11,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include diff --git a/arch/arm/mach-shmobile/intc-sh73a0.c b/arch/arm/mach-shmobile/intc-sh73a0.c index 44457a94897b..9e3618028acc 100644 --- a/arch/arm/mach-shmobile/intc-sh73a0.c +++ b/arch/arm/mach-shmobile/intc-sh73a0.c @@ -11,10 +11,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include diff --git a/arch/arm/mach-shmobile/r8a7740.h b/arch/arm/mach-shmobile/r8a7740.h index f369b4b0863d..ca7805ad7ea3 100644 --- a/arch/arm/mach-shmobile/r8a7740.h +++ b/arch/arm/mach-shmobile/r8a7740.h @@ -10,10 +10,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __ASM_R8A7740_H__ diff --git a/arch/arm/mach-shmobile/r8a7778.h b/arch/arm/mach-shmobile/r8a7778.h index f4076a50e970..9086dfc6746a 100644 --- a/arch/arm/mach-shmobile/r8a7778.h +++ b/arch/arm/mach-shmobile/r8a7778.h @@ -11,10 +11,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __ASM_R8A7778_H__ #define __ASM_R8A7778_H__ diff --git a/arch/arm/mach-shmobile/setup-emev2.c b/arch/arm/mach-shmobile/setup-emev2.c index b06a9e8f59a5..aad97be9cbe1 100644 --- a/arch/arm/mach-shmobile/setup-emev2.c +++ b/arch/arm/mach-shmobile/setup-emev2.c @@ -11,10 +11,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include diff --git a/arch/arm/mach-shmobile/setup-r7s72100.c b/arch/arm/mach-shmobile/setup-r7s72100.c index 4122104359f9..171174777b6f 100644 --- a/arch/arm/mach-shmobile/setup-r7s72100.c +++ b/arch/arm/mach-shmobile/setup-r7s72100.c @@ -12,10 +12,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include diff --git a/arch/arm/mach-shmobile/setup-r8a73a4.c b/arch/arm/mach-shmobile/setup-r8a73a4.c index 53f40b70680d..b88b88a40a3c 100644 --- a/arch/arm/mach-shmobile/setup-r8a73a4.c +++ b/arch/arm/mach-shmobile/setup-r8a73a4.c @@ -12,10 +12,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include diff --git a/arch/arm/mach-shmobile/setup-r8a7740.c b/arch/arm/mach-shmobile/setup-r8a7740.c index 8894e1b7ab0e..fe15dd26d15d 100644 --- a/arch/arm/mach-shmobile/setup-r8a7740.c +++ b/arch/arm/mach-shmobile/setup-r8a7740.c @@ -12,10 +12,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include diff --git a/arch/arm/mach-shmobile/setup-r8a7778.c b/arch/arm/mach-shmobile/setup-r8a7778.c index 85fe016d6a87..8ec784fc6b26 100644 --- a/arch/arm/mach-shmobile/setup-r8a7778.c +++ b/arch/arm/mach-shmobile/setup-r8a7778.c @@ -13,10 +13,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include diff --git a/arch/arm/mach-shmobile/setup-r8a7779.c b/arch/arm/mach-shmobile/setup-r8a7779.c index 136078ab9407..d08e75cceaab 100644 --- a/arch/arm/mach-shmobile/setup-r8a7779.c +++ b/arch/arm/mach-shmobile/setup-r8a7779.c @@ -13,10 +13,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include diff --git a/arch/arm/mach-shmobile/setup-r8a7790.c b/arch/arm/mach-shmobile/setup-r8a7790.c index 877fdeb985d0..ec7d97dca4de 100644 --- a/arch/arm/mach-shmobile/setup-r8a7790.c +++ b/arch/arm/mach-shmobile/setup-r8a7790.c @@ -12,10 +12,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include diff --git a/arch/arm/mach-shmobile/setup-r8a7791.c b/arch/arm/mach-shmobile/setup-r8a7791.c index 35d78639244f..d930925f8f1a 100644 --- a/arch/arm/mach-shmobile/setup-r8a7791.c +++ b/arch/arm/mach-shmobile/setup-r8a7791.c @@ -13,10 +13,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include diff --git a/arch/arm/mach-shmobile/setup-rcar-gen2.c b/arch/arm/mach-shmobile/setup-rcar-gen2.c index 42d5b4308923..a669377aea57 100644 --- a/arch/arm/mach-shmobile/setup-rcar-gen2.c +++ b/arch/arm/mach-shmobile/setup-rcar-gen2.c @@ -12,10 +12,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include diff --git a/arch/arm/mach-shmobile/setup-sh7372.c b/arch/arm/mach-shmobile/setup-sh7372.c index d646c8d12423..e81c38538e13 100644 --- a/arch/arm/mach-shmobile/setup-sh7372.c +++ b/arch/arm/mach-shmobile/setup-sh7372.c @@ -12,10 +12,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include diff --git a/arch/arm/mach-shmobile/setup-sh73a0.c b/arch/arm/mach-shmobile/setup-sh73a0.c index b7bd8e509668..1c8172dc2c6c 100644 --- a/arch/arm/mach-shmobile/setup-sh73a0.c +++ b/arch/arm/mach-shmobile/setup-sh73a0.c @@ -13,10 +13,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include diff --git a/arch/arm/mach-shmobile/sleep-sh7372.S b/arch/arm/mach-shmobile/sleep-sh7372.S index 9782862899e8..146b8de16432 100644 --- a/arch/arm/mach-shmobile/sleep-sh7372.S +++ b/arch/arm/mach-shmobile/sleep-sh7372.S @@ -22,11 +22,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA */ #include diff --git a/arch/arm/mach-shmobile/smp-emev2.c b/arch/arm/mach-shmobile/smp-emev2.c index 6ff1df1df9a7..baff3b5efed8 100644 --- a/arch/arm/mach-shmobile/smp-emev2.c +++ b/arch/arm/mach-shmobile/smp-emev2.c @@ -12,10 +12,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include diff --git a/arch/arm/mach-shmobile/smp-r8a7779.c b/arch/arm/mach-shmobile/smp-r8a7779.c index 3100e355c3fd..3f761f839043 100644 --- a/arch/arm/mach-shmobile/smp-r8a7779.c +++ b/arch/arm/mach-shmobile/smp-r8a7779.c @@ -12,10 +12,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include diff --git a/arch/arm/mach-shmobile/smp-sh73a0.c b/arch/arm/mach-shmobile/smp-sh73a0.c index 22d8f87b23e9..c16dbfe9836c 100644 --- a/arch/arm/mach-shmobile/smp-sh73a0.c +++ b/arch/arm/mach-shmobile/smp-sh73a0.c @@ -12,10 +12,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include diff --git a/arch/arm/mach-shmobile/timer.c b/arch/arm/mach-shmobile/timer.c index 87c6be1e79bd..1081b763e0f3 100644 --- a/arch/arm/mach-shmobile/timer.c +++ b/arch/arm/mach-shmobile/timer.c @@ -12,11 +12,6 @@ * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * */ #include #include diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 3bf999134bcc..1a77a49d2695 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -1125,9 +1125,9 @@ EXPORT_SYMBOL(drm_edid_is_valid); * Return: 0 on success or -1 on failure. */ static int -drm_do_probe_ddc_edid(struct i2c_adapter *adapter, unsigned char *buf, - int block, int len) +drm_do_probe_ddc_edid(void *data, u8 *buf, unsigned int block, size_t len) { + struct i2c_adapter *adapter = data; unsigned char start = block * EDID_LENGTH; unsigned char segment = block >> 1; unsigned char xfers = segment ? 3 : 2; @@ -1184,8 +1184,26 @@ static bool drm_edid_is_zero(u8 *in_edid, int length) return true; } -static u8 * -drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) +/** + * drm_do_get_edid - get EDID data using a custom EDID block read function + * @connector: connector we're probing + * @get_edid_block: EDID block read function + * @data: private data passed to the block read function + * + * When the I2C adapter connected to the DDC bus is hidden behind a device that + * exposes a different interface to read EDID blocks this function can be used + * to get EDID data using a custom block read function. + * + * As in the general case the DDC bus is accessible by the kernel at the I2C + * level, drivers must make all reasonable efforts to expose it as an I2C + * adapter and use drm_get_edid() instead of abusing this function. + * + * Return: Pointer to valid EDID or NULL if we couldn't find any. + */ +struct edid *drm_do_get_edid(struct drm_connector *connector, + int (*get_edid_block)(void *data, u8 *buf, unsigned int block, + size_t len), + void *data) { int i, j = 0, valid_extensions = 0; u8 *block, *new; @@ -1196,7 +1214,7 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) /* base block fetch */ for (i = 0; i < 4; i++) { - if (drm_do_probe_ddc_edid(adapter, block, 0, EDID_LENGTH)) + if (get_edid_block(data, block, 0, EDID_LENGTH)) goto out; if (drm_edid_block_valid(block, 0, print_bad_edid)) break; @@ -1210,7 +1228,7 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) /* if there's no extensions, we're done */ if (block[0x7e] == 0) - return block; + return (struct edid *)block; new = krealloc(block, (block[0x7e] + 1) * EDID_LENGTH, GFP_KERNEL); if (!new) @@ -1219,7 +1237,7 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) for (j = 1; j <= block[0x7e]; j++) { for (i = 0; i < 4; i++) { - if (drm_do_probe_ddc_edid(adapter, + if (get_edid_block(data, block + (valid_extensions + 1) * EDID_LENGTH, j, EDID_LENGTH)) goto out; @@ -1247,7 +1265,7 @@ drm_do_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) block = new; } - return block; + return (struct edid *)block; carp: if (print_bad_edid) { @@ -1260,6 +1278,7 @@ out: kfree(block); return NULL; } +EXPORT_SYMBOL_GPL(drm_do_get_edid); /** * drm_probe_ddc() - probe DDC presence @@ -1289,12 +1308,10 @@ EXPORT_SYMBOL(drm_probe_ddc); struct edid *drm_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) { - struct edid *edid = NULL; + if (!drm_probe_ddc(adapter)) + return NULL; - if (drm_probe_ddc(adapter)) - edid = (struct edid *)drm_do_get_edid(connector, adapter); - - return edid; + return drm_do_get_edid(connector, drm_do_probe_ddc_edid, adapter); } EXPORT_SYMBOL(drm_get_edid); diff --git a/drivers/gpu/drm/i2c/Kconfig b/drivers/gpu/drm/i2c/Kconfig index 4d341db462a2..22c7ed63a001 100644 --- a/drivers/gpu/drm/i2c/Kconfig +++ b/drivers/gpu/drm/i2c/Kconfig @@ -1,6 +1,12 @@ menu "I2C encoder or helper chips" depends on DRM && DRM_KMS_HELPER && I2C +config DRM_I2C_ADV7511 + tristate "AV7511 encoder" + select REGMAP_I2C + help + Support for the Analog Device ADV7511(W) and ADV7513 HDMI encoders. + config DRM_I2C_CH7006 tristate "Chrontel ch7006 TV encoder" default m if DRM_NOUVEAU diff --git a/drivers/gpu/drm/i2c/Makefile b/drivers/gpu/drm/i2c/Makefile index 43aa33baebed..2c72eb584ab7 100644 --- a/drivers/gpu/drm/i2c/Makefile +++ b/drivers/gpu/drm/i2c/Makefile @@ -1,5 +1,7 @@ ccflags-y := -Iinclude/drm +obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511.o + ch7006-y := ch7006_drv.o ch7006_mode.o obj-$(CONFIG_DRM_I2C_CH7006) += ch7006.o diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c new file mode 100644 index 000000000000..faf1c0c5ab2e --- /dev/null +++ b/drivers/gpu/drm/i2c/adv7511.c @@ -0,0 +1,1010 @@ +/* + * Analog Devices ADV7511 HDMI transmitter driver + * + * Copyright 2012 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "adv7511.h" + +struct adv7511 { + struct i2c_client *i2c_main; + struct i2c_client *i2c_edid; + + struct regmap *regmap; + struct regmap *packet_memory_regmap; + enum drm_connector_status status; + int dpms_mode; + + unsigned int f_tmds; + + unsigned int current_edid_segment; + uint8_t edid_buf[256]; + + wait_queue_head_t wq; + struct drm_encoder *encoder; + + bool embedded_sync; + enum adv7511_sync_polarity vsync_polarity; + enum adv7511_sync_polarity hsync_polarity; + bool rgb; + + struct edid *edid; + + struct gpio_desc *gpio_pd; +}; + +static struct adv7511 *encoder_to_adv7511(struct drm_encoder *encoder) +{ + return to_encoder_slave(encoder)->slave_priv; +} + +/* ADI recommended values for proper operation. */ +static const struct reg_default adv7511_fixed_registers[] = { + { 0x98, 0x03 }, + { 0x9a, 0xe0 }, + { 0x9c, 0x30 }, + { 0x9d, 0x61 }, + { 0xa2, 0xa4 }, + { 0xa3, 0xa4 }, + { 0xe0, 0xd0 }, + { 0xf9, 0x00 }, + { 0x55, 0x02 }, +}; + +/* ----------------------------------------------------------------------------- + * Register access + */ + +static const uint8_t adv7511_register_defaults[] = { + 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 00 */ + 0x00, 0x00, 0x01, 0x0e, 0xbc, 0x18, 0x01, 0x13, + 0x25, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 10 */ + 0x46, 0x62, 0x04, 0xa8, 0x00, 0x00, 0x1c, 0x84, + 0x1c, 0xbf, 0x04, 0xa8, 0x1e, 0x70, 0x02, 0x1e, /* 20 */ + 0x00, 0x00, 0x04, 0xa8, 0x08, 0x12, 0x1b, 0xac, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 30 */ + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0, + 0x00, 0x50, 0x90, 0x7e, 0x79, 0x70, 0x00, 0x00, /* 40 */ + 0x00, 0xa8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x0d, 0x00, 0x00, 0x00, 0x00, /* 50 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 60 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 70 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 80 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 90 */ + 0x0b, 0x02, 0x00, 0x18, 0x5a, 0x60, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x80, 0x08, 0x04, 0x00, 0x00, /* a0 */ + 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x14, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* b0 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* c0 */ + 0x00, 0x03, 0x00, 0x00, 0x02, 0x00, 0x01, 0x04, + 0x30, 0xff, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, /* d0 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, + 0x80, 0x75, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, /* e0 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x11, 0x00, /* f0 */ + 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static bool adv7511_register_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case ADV7511_REG_CHIP_REVISION: + case ADV7511_REG_SPDIF_FREQ: + case ADV7511_REG_CTS_AUTOMATIC1: + case ADV7511_REG_CTS_AUTOMATIC2: + case ADV7511_REG_VIC_DETECTED: + case ADV7511_REG_VIC_SEND: + case ADV7511_REG_AUX_VIC_DETECTED: + case ADV7511_REG_STATUS: + case ADV7511_REG_GC(1): + case ADV7511_REG_INT(0): + case ADV7511_REG_INT(1): + case ADV7511_REG_PLL_STATUS: + case ADV7511_REG_AN(0): + case ADV7511_REG_AN(1): + case ADV7511_REG_AN(2): + case ADV7511_REG_AN(3): + case ADV7511_REG_AN(4): + case ADV7511_REG_AN(5): + case ADV7511_REG_AN(6): + case ADV7511_REG_AN(7): + case ADV7511_REG_HDCP_STATUS: + case ADV7511_REG_BCAPS: + case ADV7511_REG_BKSV(0): + case ADV7511_REG_BKSV(1): + case ADV7511_REG_BKSV(2): + case ADV7511_REG_BKSV(3): + case ADV7511_REG_BKSV(4): + case ADV7511_REG_DDC_STATUS: + case ADV7511_REG_BSTATUS(0): + case ADV7511_REG_BSTATUS(1): + case ADV7511_REG_CHIP_ID_HIGH: + case ADV7511_REG_CHIP_ID_LOW: + return true; + } + + return false; +} + +static const struct regmap_config adv7511_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_RBTREE, + .reg_defaults_raw = adv7511_register_defaults, + .num_reg_defaults_raw = ARRAY_SIZE(adv7511_register_defaults), + + .volatile_reg = adv7511_register_volatile, +}; + +/* ----------------------------------------------------------------------------- + * Hardware configuration + */ + +static void adv7511_set_colormap(struct adv7511 *adv7511, bool enable, + const uint16_t *coeff, + unsigned int scaling_factor) +{ + unsigned int i; + + regmap_update_bits(adv7511->regmap, ADV7511_REG_CSC_UPPER(1), + ADV7511_CSC_UPDATE_MODE, ADV7511_CSC_UPDATE_MODE); + + if (enable) { + for (i = 0; i < 12; ++i) { + regmap_update_bits(adv7511->regmap, + ADV7511_REG_CSC_UPPER(i), + 0x1f, coeff[i] >> 8); + regmap_write(adv7511->regmap, + ADV7511_REG_CSC_LOWER(i), + coeff[i] & 0xff); + } + } + + if (enable) + regmap_update_bits(adv7511->regmap, ADV7511_REG_CSC_UPPER(0), + 0xe0, 0x80 | (scaling_factor << 5)); + else + regmap_update_bits(adv7511->regmap, ADV7511_REG_CSC_UPPER(0), + 0x80, 0x00); + + regmap_update_bits(adv7511->regmap, ADV7511_REG_CSC_UPPER(1), + ADV7511_CSC_UPDATE_MODE, 0); +} + +static int adv7511_packet_enable(struct adv7511 *adv7511, unsigned int packet) +{ + if (packet & 0xff) + regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE0, + packet, 0xff); + + if (packet & 0xff00) { + packet >>= 8; + regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE1, + packet, 0xff); + } + + return 0; +} + +static int adv7511_packet_disable(struct adv7511 *adv7511, unsigned int packet) +{ + if (packet & 0xff) + regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE0, + packet, 0x00); + + if (packet & 0xff00) { + packet >>= 8; + regmap_update_bits(adv7511->regmap, ADV7511_REG_PACKET_ENABLE1, + packet, 0x00); + } + + return 0; +} + +/* Coefficients for adv7511 color space conversion */ +static const uint16_t adv7511_csc_ycbcr_to_rgb[] = { + 0x0734, 0x04ad, 0x0000, 0x1c1b, + 0x1ddc, 0x04ad, 0x1f24, 0x0135, + 0x0000, 0x04ad, 0x087c, 0x1b77, +}; + +static void adv7511_set_config_csc(struct adv7511 *adv7511, + struct drm_connector *connector, + bool rgb) +{ + struct adv7511_video_config config; + bool output_format_422, output_format_ycbcr; + unsigned int mode; + uint8_t infoframe[17]; + + if (adv7511->edid) + config.hdmi_mode = drm_detect_hdmi_monitor(adv7511->edid); + else + config.hdmi_mode = false; + + hdmi_avi_infoframe_init(&config.avi_infoframe); + + config.avi_infoframe.scan_mode = HDMI_SCAN_MODE_UNDERSCAN; + + if (rgb) { + config.csc_enable = false; + config.avi_infoframe.colorspace = HDMI_COLORSPACE_RGB; + } else { + config.csc_scaling_factor = ADV7511_CSC_SCALING_4; + config.csc_coefficents = adv7511_csc_ycbcr_to_rgb; + + if ((connector->display_info.color_formats & + DRM_COLOR_FORMAT_YCRCB422) && + config.hdmi_mode) { + config.csc_enable = false; + config.avi_infoframe.colorspace = + HDMI_COLORSPACE_YUV422; + } else { + config.csc_enable = true; + config.avi_infoframe.colorspace = HDMI_COLORSPACE_RGB; + } + } + + if (config.hdmi_mode) { + mode = ADV7511_HDMI_CFG_MODE_HDMI; + + switch (config.avi_infoframe.colorspace) { + case HDMI_COLORSPACE_YUV444: + output_format_422 = false; + output_format_ycbcr = true; + break; + case HDMI_COLORSPACE_YUV422: + output_format_422 = true; + output_format_ycbcr = true; + break; + default: + output_format_422 = false; + output_format_ycbcr = false; + break; + } + } else { + mode = ADV7511_HDMI_CFG_MODE_DVI; + output_format_422 = false; + output_format_ycbcr = false; + } + + adv7511_packet_disable(adv7511, ADV7511_PACKET_ENABLE_AVI_INFOFRAME); + + adv7511_set_colormap(adv7511, config.csc_enable, + config.csc_coefficents, + config.csc_scaling_factor); + + regmap_update_bits(adv7511->regmap, ADV7511_REG_VIDEO_INPUT_CFG1, 0x81, + (output_format_422 << 7) | output_format_ycbcr); + + regmap_update_bits(adv7511->regmap, ADV7511_REG_HDCP_HDMI_CFG, + ADV7511_HDMI_CFG_MODE_MASK, mode); + + hdmi_avi_infoframe_pack(&config.avi_infoframe, infoframe, + sizeof(infoframe)); + + /* The AVI infoframe id is not configurable */ + regmap_bulk_write(adv7511->regmap, ADV7511_REG_AVI_INFOFRAME_VERSION, + infoframe + 1, sizeof(infoframe) - 1); + + adv7511_packet_enable(adv7511, ADV7511_PACKET_ENABLE_AVI_INFOFRAME); +} + +static void adv7511_set_link_config(struct adv7511 *adv7511, + const struct adv7511_link_config *config) +{ + /* + * The input style values documented in the datasheet don't match the + * hardware register field values :-( + */ + static const unsigned int input_styles[4] = { 0, 2, 1, 3 }; + + unsigned int clock_delay; + unsigned int color_depth; + unsigned int input_id; + + clock_delay = (config->clock_delay + 1200) / 400; + color_depth = config->input_color_depth == 8 ? 3 + : (config->input_color_depth == 10 ? 1 : 2); + + /* TODO Support input ID 6 */ + if (config->input_colorspace != HDMI_COLORSPACE_YUV422) + input_id = config->input_clock == ADV7511_INPUT_CLOCK_DDR + ? 5 : 0; + else if (config->input_clock == ADV7511_INPUT_CLOCK_DDR) + input_id = config->embedded_sync ? 8 : 7; + else if (config->input_clock == ADV7511_INPUT_CLOCK_2X) + input_id = config->embedded_sync ? 4 : 3; + else + input_id = config->embedded_sync ? 2 : 1; + + regmap_update_bits(adv7511->regmap, ADV7511_REG_I2C_FREQ_ID_CFG, 0xf, + input_id); + regmap_update_bits(adv7511->regmap, ADV7511_REG_VIDEO_INPUT_CFG1, 0x7e, + (color_depth << 4) | + (input_styles[config->input_style] << 2)); + regmap_write(adv7511->regmap, ADV7511_REG_VIDEO_INPUT_CFG2, + config->input_justification << 3); + regmap_write(adv7511->regmap, ADV7511_REG_TIMING_GEN_SEQ, + config->sync_pulse << 2); + + regmap_write(adv7511->regmap, 0xba, clock_delay << 5); + + adv7511->embedded_sync = config->embedded_sync; + adv7511->hsync_polarity = config->hsync_polarity; + adv7511->vsync_polarity = config->vsync_polarity; + adv7511->rgb = config->input_colorspace == HDMI_COLORSPACE_RGB; +} + +/* ----------------------------------------------------------------------------- + * Interrupt and hotplug detection + */ + +static bool adv7511_hpd(struct adv7511 *adv7511) +{ + unsigned int irq0; + int ret; + + ret = regmap_read(adv7511->regmap, ADV7511_REG_INT(0), &irq0); + if (ret < 0) + return false; + + if (irq0 & ADV7511_INT0_HDP) { + regmap_write(adv7511->regmap, ADV7511_REG_INT(0), + ADV7511_INT0_HDP); + return true; + } + + return false; +} + +static irqreturn_t adv7511_irq_handler(int irq, void *devid) +{ + struct adv7511 *adv7511 = devid; + + if (adv7511_hpd(adv7511)) + drm_helper_hpd_irq_event(adv7511->encoder->dev); + + wake_up_all(&adv7511->wq); + + return IRQ_HANDLED; +} + +static unsigned int adv7511_is_interrupt_pending(struct adv7511 *adv7511, + unsigned int irq) +{ + unsigned int irq0, irq1; + unsigned int pending; + int ret; + + ret = regmap_read(adv7511->regmap, ADV7511_REG_INT(0), &irq0); + if (ret < 0) + return 0; + ret = regmap_read(adv7511->regmap, ADV7511_REG_INT(1), &irq1); + if (ret < 0) + return 0; + + pending = (irq1 << 8) | irq0; + + return pending & irq; +} + +static int adv7511_wait_for_interrupt(struct adv7511 *adv7511, int irq, + int timeout) +{ + unsigned int pending; + int ret; + + if (adv7511->i2c_main->irq) { + ret = wait_event_interruptible_timeout(adv7511->wq, + adv7511_is_interrupt_pending(adv7511, irq), + msecs_to_jiffies(timeout)); + if (ret <= 0) + return 0; + pending = adv7511_is_interrupt_pending(adv7511, irq); + } else { + if (timeout < 25) + timeout = 25; + do { + pending = adv7511_is_interrupt_pending(adv7511, irq); + if (pending) + break; + msleep(25); + timeout -= 25; + } while (timeout >= 25); + } + + return pending; +} + +/* ----------------------------------------------------------------------------- + * EDID retrieval + */ + +static int adv7511_get_edid_block(void *data, u8 *buf, unsigned int block, + size_t len) +{ + struct adv7511 *adv7511 = data; + struct i2c_msg xfer[2]; + uint8_t offset; + unsigned int i; + int ret; + + if (len > 128) + return -EINVAL; + + if (adv7511->current_edid_segment != block / 2) { + unsigned int status; + + ret = regmap_read(adv7511->regmap, ADV7511_REG_DDC_STATUS, + &status); + if (ret < 0) + return ret; + + if (status != 2) { + regmap_write(adv7511->regmap, ADV7511_REG_EDID_SEGMENT, + block); + ret = adv7511_wait_for_interrupt(adv7511, + ADV7511_INT0_EDID_READY | + ADV7511_INT1_DDC_ERROR, 200); + + if (!(ret & ADV7511_INT0_EDID_READY)) + return -EIO; + } + + regmap_write(adv7511->regmap, ADV7511_REG_INT(0), + ADV7511_INT0_EDID_READY | ADV7511_INT1_DDC_ERROR); + + /* Break this apart, hopefully more I2C controllers will + * support 64 byte transfers than 256 byte transfers + */ + + xfer[0].addr = adv7511->i2c_edid->addr; + xfer[0].flags = 0; + xfer[0].len = 1; + xfer[0].buf = &offset; + xfer[1].addr = adv7511->i2c_edid->addr; + xfer[1].flags = I2C_M_RD; + xfer[1].len = 64; + xfer[1].buf = adv7511->edid_buf; + + offset = 0; + + for (i = 0; i < 4; ++i) { + ret = i2c_transfer(adv7511->i2c_edid->adapter, xfer, + ARRAY_SIZE(xfer)); + if (ret < 0) + return ret; + else if (ret != 2) + return -EIO; + + xfer[1].buf += 64; + offset += 64; + } + + adv7511->current_edid_segment = block / 2; + } + + if (block % 2 == 0) + memcpy(buf, adv7511->edid_buf, len); + else + memcpy(buf, adv7511->edid_buf + 128, len); + + return 0; +} + +/* ----------------------------------------------------------------------------- + * Encoder operations + */ + +static int adv7511_get_modes(struct drm_encoder *encoder, + struct drm_connector *connector) +{ + struct adv7511 *adv7511 = encoder_to_adv7511(encoder); + struct edid *edid; + unsigned int count; + + /* Reading the EDID only works if the device is powered */ + if (adv7511->dpms_mode != DRM_MODE_DPMS_ON) { + regmap_write(adv7511->regmap, ADV7511_REG_INT(0), + ADV7511_INT0_EDID_READY | ADV7511_INT1_DDC_ERROR); + regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, + ADV7511_POWER_POWER_DOWN, 0); + adv7511->current_edid_segment = -1; + } + + edid = drm_do_get_edid(connector, adv7511_get_edid_block, adv7511); + + if (adv7511->dpms_mode != DRM_MODE_DPMS_ON) + regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, + ADV7511_POWER_POWER_DOWN, + ADV7511_POWER_POWER_DOWN); + + kfree(adv7511->edid); + adv7511->edid = edid; + if (!edid) + return 0; + + drm_mode_connector_update_edid_property(connector, edid); + count = drm_add_edid_modes(connector, edid); + + adv7511_set_config_csc(adv7511, connector, adv7511->rgb); + + return count; +} + +static void adv7511_encoder_dpms(struct drm_encoder *encoder, int mode) +{ + struct adv7511 *adv7511 = encoder_to_adv7511(encoder); + + switch (mode) { + case DRM_MODE_DPMS_ON: + adv7511->current_edid_segment = -1; + + regmap_write(adv7511->regmap, ADV7511_REG_INT(0), + ADV7511_INT0_EDID_READY | ADV7511_INT1_DDC_ERROR); + regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, + ADV7511_POWER_POWER_DOWN, 0); + /* + * Per spec it is allowed to pulse the HDP signal to indicate + * that the EDID information has changed. Some monitors do this + * when they wakeup from standby or are enabled. When the HDP + * goes low the adv7511 is reset and the outputs are disabled + * which might cause the monitor to go to standby again. To + * avoid this we ignore the HDP pin for the first few seconds + * after enabeling the output. + */ + regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, + ADV7511_REG_POWER2_HDP_SRC_MASK, + ADV7511_REG_POWER2_HDP_SRC_NONE); + /* Most of the registers are reset during power down or + * when HPD is low + */ + regcache_sync(adv7511->regmap); + break; + default: + /* TODO: setup additional power down modes */ + regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, + ADV7511_POWER_POWER_DOWN, + ADV7511_POWER_POWER_DOWN); + regcache_mark_dirty(adv7511->regmap); + break; + } + + adv7511->dpms_mode = mode; +} + +static enum drm_connector_status +adv7511_encoder_detect(struct drm_encoder *encoder, + struct drm_connector *connector) +{ + struct adv7511 *adv7511 = encoder_to_adv7511(encoder); + enum drm_connector_status status; + unsigned int val; + bool hpd; + int ret; + + ret = regmap_read(adv7511->regmap, ADV7511_REG_STATUS, &val); + if (ret < 0) + return connector_status_disconnected; + + if (val & ADV7511_STATUS_HPD) + status = connector_status_connected; + else + status = connector_status_disconnected; + + hpd = adv7511_hpd(adv7511); + + /* The chip resets itself when the cable is disconnected, so in case + * there is a pending HPD interrupt and the cable is connected there was + * at least one transition from disconnected to connected and the chip + * has to be reinitialized. */ + if (status == connector_status_connected && hpd && + adv7511->dpms_mode == DRM_MODE_DPMS_ON) { + regcache_mark_dirty(adv7511->regmap); + adv7511_encoder_dpms(encoder, adv7511->dpms_mode); + adv7511_get_modes(encoder, connector); + if (adv7511->status == connector_status_connected) + status = connector_status_disconnected; + } else { + /* Renable HDP sensing */ + regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, + ADV7511_REG_POWER2_HDP_SRC_MASK, + ADV7511_REG_POWER2_HDP_SRC_BOTH); + } + + adv7511->status = status; + return status; +} + +static int adv7511_encoder_mode_valid(struct drm_encoder *encoder, + struct drm_display_mode *mode) +{ + if (mode->clock > 165000) + return MODE_CLOCK_HIGH; + + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + return MODE_NO_INTERLACE; + + return MODE_OK; +} + +static void adv7511_encoder_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adj_mode) +{ + struct adv7511 *adv7511 = encoder_to_adv7511(encoder); + unsigned int low_refresh_rate; + unsigned int hsync_polarity = 0; + unsigned int vsync_polarity = 0; + + if (adv7511->embedded_sync) { + unsigned int hsync_offset, hsync_len; + unsigned int vsync_offset, vsync_len; + + hsync_offset = adj_mode->crtc_hsync_start - + adj_mode->crtc_hdisplay; + vsync_offset = adj_mode->crtc_vsync_start - + adj_mode->crtc_vdisplay; + hsync_len = adj_mode->crtc_hsync_end - + adj_mode->crtc_hsync_start; + vsync_len = adj_mode->crtc_vsync_end - + adj_mode->crtc_vsync_start; + + /* The hardware vsync generator has a off-by-one bug */ + vsync_offset += 1; + + regmap_write(adv7511->regmap, ADV7511_REG_HSYNC_PLACEMENT_MSB, + ((hsync_offset >> 10) & 0x7) << 5); + regmap_write(adv7511->regmap, ADV7511_REG_SYNC_DECODER(0), + (hsync_offset >> 2) & 0xff); + regmap_write(adv7511->regmap, ADV7511_REG_SYNC_DECODER(1), + ((hsync_offset & 0x3) << 6) | + ((hsync_len >> 4) & 0x3f)); + regmap_write(adv7511->regmap, ADV7511_REG_SYNC_DECODER(2), + ((hsync_len & 0xf) << 4) | + ((vsync_offset >> 6) & 0xf)); + regmap_write(adv7511->regmap, ADV7511_REG_SYNC_DECODER(3), + ((vsync_offset & 0x3f) << 2) | + ((vsync_len >> 8) & 0x3)); + regmap_write(adv7511->regmap, ADV7511_REG_SYNC_DECODER(4), + vsync_len & 0xff); + + hsync_polarity = !(adj_mode->flags & DRM_MODE_FLAG_PHSYNC); + vsync_polarity = !(adj_mode->flags & DRM_MODE_FLAG_PVSYNC); + } else { + enum adv7511_sync_polarity mode_hsync_polarity; + enum adv7511_sync_polarity mode_vsync_polarity; + + /** + * If the input signal is always low or always high we want to + * invert or let it passthrough depending on the polarity of the + * current mode. + **/ + if (adj_mode->flags & DRM_MODE_FLAG_NHSYNC) + mode_hsync_polarity = ADV7511_SYNC_POLARITY_LOW; + else + mode_hsync_polarity = ADV7511_SYNC_POLARITY_HIGH; + + if (adj_mode->flags & DRM_MODE_FLAG_NVSYNC) + mode_vsync_polarity = ADV7511_SYNC_POLARITY_LOW; + else + mode_vsync_polarity = ADV7511_SYNC_POLARITY_HIGH; + + if (adv7511->hsync_polarity != mode_hsync_polarity && + adv7511->hsync_polarity != + ADV7511_SYNC_POLARITY_PASSTHROUGH) + hsync_polarity = 1; + + if (adv7511->vsync_polarity != mode_vsync_polarity && + adv7511->vsync_polarity != + ADV7511_SYNC_POLARITY_PASSTHROUGH) + vsync_polarity = 1; + } + + if (mode->vrefresh <= 24000) + low_refresh_rate = ADV7511_LOW_REFRESH_RATE_24HZ; + else if (mode->vrefresh <= 25000) + low_refresh_rate = ADV7511_LOW_REFRESH_RATE_25HZ; + else if (mode->vrefresh <= 30000) + low_refresh_rate = ADV7511_LOW_REFRESH_RATE_30HZ; + else + low_refresh_rate = ADV7511_LOW_REFRESH_RATE_NONE; + + regmap_update_bits(adv7511->regmap, 0xfb, + 0x6, low_refresh_rate << 1); + regmap_update_bits(adv7511->regmap, 0x17, + 0x60, (vsync_polarity << 6) | (hsync_polarity << 5)); + + /* + * TODO Test first order 4:2:2 to 4:4:4 up conversion method, which is + * supposed to give better results. + */ + + adv7511->f_tmds = mode->clock; +} + +static struct drm_encoder_slave_funcs adv7511_encoder_funcs = { + .dpms = adv7511_encoder_dpms, + .mode_valid = adv7511_encoder_mode_valid, + .mode_set = adv7511_encoder_mode_set, + .detect = adv7511_encoder_detect, + .get_modes = adv7511_get_modes, +}; + +/* ----------------------------------------------------------------------------- + * Probe & remove + */ + +static int adv7511_parse_dt(struct device_node *np, + struct adv7511_link_config *config) +{ + const char *str; + int ret; + + memset(config, 0, sizeof(*config)); + + of_property_read_u32(np, "adi,input-depth", &config->input_color_depth); + if (config->input_color_depth != 8 && config->input_color_depth != 10 && + config->input_color_depth != 12) + return -EINVAL; + + ret = of_property_read_string(np, "adi,input-colorspace", &str); + if (ret < 0) + return ret; + + if (!strcmp(str, "rgb")) + config->input_colorspace = HDMI_COLORSPACE_RGB; + else if (!strcmp(str, "yuv422")) + config->input_colorspace = HDMI_COLORSPACE_YUV422; + else if (!strcmp(str, "yuv444")) + config->input_colorspace = HDMI_COLORSPACE_YUV444; + else + return -EINVAL; + + ret = of_property_read_string(np, "adi,input-clock", &str); + if (ret < 0) + return ret; + + if (!strcmp(str, "1x")) + config->input_clock = ADV7511_INPUT_CLOCK_1X; + else if (!strcmp(str, "2x")) + config->input_clock = ADV7511_INPUT_CLOCK_2X; + else if (!strcmp(str, "ddr")) + config->input_clock = ADV7511_INPUT_CLOCK_DDR; + else + return -EINVAL; + + if (config->input_colorspace == HDMI_COLORSPACE_YUV422 || + config->input_clock != ADV7511_INPUT_CLOCK_1X) { + ret = of_property_read_u32(np, "adi,input-style", + &config->input_style); + if (ret) + return ret; + + if (config->input_style < 1 || config->input_style > 3) + return -EINVAL; + + ret = of_property_read_string(np, "adi,input-justification", + &str); + if (ret < 0) + return ret; + + if (!strcmp(str, "left")) + config->input_justification = + ADV7511_INPUT_JUSTIFICATION_LEFT; + else if (!strcmp(str, "evenly")) + config->input_justification = + ADV7511_INPUT_JUSTIFICATION_EVENLY; + else if (!strcmp(str, "right")) + config->input_justification = + ADV7511_INPUT_JUSTIFICATION_RIGHT; + else + return -EINVAL; + + } else { + config->input_style = 1; + config->input_justification = ADV7511_INPUT_JUSTIFICATION_LEFT; + } + + of_property_read_u32(np, "adi,clock-delay", &config->clock_delay); + if (config->clock_delay < -1200 || config->clock_delay > 1600) + return -EINVAL; + + config->embedded_sync = of_property_read_bool(np, "adi,embedded-sync"); + + /* Hardcode the sync pulse configurations for now. */ + config->sync_pulse = ADV7511_INPUT_SYNC_PULSE_NONE; + config->vsync_polarity = ADV7511_SYNC_POLARITY_PASSTHROUGH; + config->hsync_polarity = ADV7511_SYNC_POLARITY_PASSTHROUGH; + + return 0; +} + +static const int edid_i2c_addr = 0x7e; +static const int packet_i2c_addr = 0x70; +static const int cec_i2c_addr = 0x78; + +static int adv7511_probe(struct i2c_client *i2c, const struct i2c_device_id *id) +{ + struct adv7511_link_config link_config; + struct adv7511 *adv7511; + struct device *dev = &i2c->dev; + unsigned int val; + int ret; + + if (!dev->of_node) + return -EINVAL; + + adv7511 = devm_kzalloc(dev, sizeof(*adv7511), GFP_KERNEL); + if (!adv7511) + return -ENOMEM; + + adv7511->dpms_mode = DRM_MODE_DPMS_OFF; + adv7511->status = connector_status_disconnected; + + ret = adv7511_parse_dt(dev->of_node, &link_config); + if (ret) + return ret; + + /* + * The power down GPIO is optional. If present, toggle it from active to + * inactive to wake up the encoder. + */ + adv7511->gpio_pd = devm_gpiod_get_optional(dev, "pd", GPIOD_OUT_HIGH); + if (IS_ERR(adv7511->gpio_pd)) + return PTR_ERR(adv7511->gpio_pd); + + if (adv7511->gpio_pd) { + mdelay(5); + gpiod_set_value_cansleep(adv7511->gpio_pd, 0); + } + + adv7511->regmap = devm_regmap_init_i2c(i2c, &adv7511_regmap_config); + if (IS_ERR(adv7511->regmap)) + return PTR_ERR(adv7511->regmap); + + ret = regmap_read(adv7511->regmap, ADV7511_REG_CHIP_REVISION, &val); + if (ret) + return ret; + dev_dbg(dev, "Rev. %d\n", val); + + ret = regmap_register_patch(adv7511->regmap, adv7511_fixed_registers, + ARRAY_SIZE(adv7511_fixed_registers)); + if (ret) + return ret; + + regmap_write(adv7511->regmap, ADV7511_REG_EDID_I2C_ADDR, edid_i2c_addr); + regmap_write(adv7511->regmap, ADV7511_REG_PACKET_I2C_ADDR, + packet_i2c_addr); + regmap_write(adv7511->regmap, ADV7511_REG_CEC_I2C_ADDR, cec_i2c_addr); + adv7511_packet_disable(adv7511, 0xffff); + + adv7511->i2c_main = i2c; + adv7511->i2c_edid = i2c_new_dummy(i2c->adapter, edid_i2c_addr >> 1); + if (!adv7511->i2c_edid) + return -ENOMEM; + + if (i2c->irq) { + init_waitqueue_head(&adv7511->wq); + + ret = devm_request_threaded_irq(dev, i2c->irq, NULL, + adv7511_irq_handler, + IRQF_ONESHOT, dev_name(dev), + adv7511); + if (ret) + goto err_i2c_unregister_device; + } + + /* CEC is unused for now */ + regmap_write(adv7511->regmap, ADV7511_REG_CEC_CTRL, + ADV7511_CEC_CTRL_POWER_DOWN); + + regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, + ADV7511_POWER_POWER_DOWN, ADV7511_POWER_POWER_DOWN); + + adv7511->current_edid_segment = -1; + + i2c_set_clientdata(i2c, adv7511); + + adv7511_set_link_config(adv7511, &link_config); + + return 0; + +err_i2c_unregister_device: + i2c_unregister_device(adv7511->i2c_edid); + + return ret; +} + +static int adv7511_remove(struct i2c_client *i2c) +{ + struct adv7511 *adv7511 = i2c_get_clientdata(i2c); + + i2c_unregister_device(adv7511->i2c_edid); + + kfree(adv7511->edid); + + return 0; +} + +static int adv7511_encoder_init(struct i2c_client *i2c, struct drm_device *dev, + struct drm_encoder_slave *encoder) +{ + + struct adv7511 *adv7511 = i2c_get_clientdata(i2c); + + encoder->slave_priv = adv7511; + encoder->slave_funcs = &adv7511_encoder_funcs; + + adv7511->encoder = &encoder->base; + + return 0; +} + +static const struct i2c_device_id adv7511_i2c_ids[] = { + { "adv7511", 0 }, + { "adv7511w", 0 }, + { "adv7513", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, adv7511_i2c_ids); + +static const struct of_device_id adv7511_of_ids[] = { + { .compatible = "adi,adv7511", }, + { .compatible = "adi,adv7511w", }, + { .compatible = "adi,adv7513", }, + { } +}; +MODULE_DEVICE_TABLE(of, adv7511_of_ids); + +static struct drm_i2c_encoder_driver adv7511_driver = { + .i2c_driver = { + .driver = { + .name = "adv7511", + .of_match_table = adv7511_of_ids, + }, + .id_table = adv7511_i2c_ids, + .probe = adv7511_probe, + .remove = adv7511_remove, + }, + + .encoder_init = adv7511_encoder_init, +}; + +static int __init adv7511_init(void) +{ + return drm_i2c_encoder_register(THIS_MODULE, &adv7511_driver); +} +module_init(adv7511_init); + +static void __exit adv7511_exit(void) +{ + drm_i2c_encoder_unregister(&adv7511_driver); +} +module_exit(adv7511_exit); + +MODULE_AUTHOR("Lars-Peter Clausen "); +MODULE_DESCRIPTION("ADV7511 HDMI transmitter driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/i2c/adv7511.h b/drivers/gpu/drm/i2c/adv7511.h new file mode 100644 index 000000000000..6599ed538426 --- /dev/null +++ b/drivers/gpu/drm/i2c/adv7511.h @@ -0,0 +1,289 @@ +/* + * Analog Devices ADV7511 HDMI transmitter driver + * + * Copyright 2012 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#ifndef __DRM_I2C_ADV7511_H__ +#define __DRM_I2C_ADV7511_H__ + +#include + +#define ADV7511_REG_CHIP_REVISION 0x00 +#define ADV7511_REG_N0 0x01 +#define ADV7511_REG_N1 0x02 +#define ADV7511_REG_N2 0x03 +#define ADV7511_REG_SPDIF_FREQ 0x04 +#define ADV7511_REG_CTS_AUTOMATIC1 0x05 +#define ADV7511_REG_CTS_AUTOMATIC2 0x06 +#define ADV7511_REG_CTS_MANUAL0 0x07 +#define ADV7511_REG_CTS_MANUAL1 0x08 +#define ADV7511_REG_CTS_MANUAL2 0x09 +#define ADV7511_REG_AUDIO_SOURCE 0x0a +#define ADV7511_REG_AUDIO_CONFIG 0x0b +#define ADV7511_REG_I2S_CONFIG 0x0c +#define ADV7511_REG_I2S_WIDTH 0x0d +#define ADV7511_REG_AUDIO_SUB_SRC0 0x0e +#define ADV7511_REG_AUDIO_SUB_SRC1 0x0f +#define ADV7511_REG_AUDIO_SUB_SRC2 0x10 +#define ADV7511_REG_AUDIO_SUB_SRC3 0x11 +#define ADV7511_REG_AUDIO_CFG1 0x12 +#define ADV7511_REG_AUDIO_CFG2 0x13 +#define ADV7511_REG_AUDIO_CFG3 0x14 +#define ADV7511_REG_I2C_FREQ_ID_CFG 0x15 +#define ADV7511_REG_VIDEO_INPUT_CFG1 0x16 +#define ADV7511_REG_CSC_UPPER(x) (0x18 + (x) * 2) +#define ADV7511_REG_CSC_LOWER(x) (0x19 + (x) * 2) +#define ADV7511_REG_SYNC_DECODER(x) (0x30 + (x)) +#define ADV7511_REG_DE_GENERATOR (0x35 + (x)) +#define ADV7511_REG_PIXEL_REPETITION 0x3b +#define ADV7511_REG_VIC_MANUAL 0x3c +#define ADV7511_REG_VIC_SEND 0x3d +#define ADV7511_REG_VIC_DETECTED 0x3e +#define ADV7511_REG_AUX_VIC_DETECTED 0x3f +#define ADV7511_REG_PACKET_ENABLE0 0x40 +#define ADV7511_REG_POWER 0x41 +#define ADV7511_REG_STATUS 0x42 +#define ADV7511_REG_EDID_I2C_ADDR 0x43 +#define ADV7511_REG_PACKET_ENABLE1 0x44 +#define ADV7511_REG_PACKET_I2C_ADDR 0x45 +#define ADV7511_REG_DSD_ENABLE 0x46 +#define ADV7511_REG_VIDEO_INPUT_CFG2 0x48 +#define ADV7511_REG_INFOFRAME_UPDATE 0x4a +#define ADV7511_REG_GC(x) (0x4b + (x)) /* 0x4b - 0x51 */ +#define ADV7511_REG_AVI_INFOFRAME_VERSION 0x52 +#define ADV7511_REG_AVI_INFOFRAME_LENGTH 0x53 +#define ADV7511_REG_AVI_INFOFRAME_CHECKSUM 0x54 +#define ADV7511_REG_AVI_INFOFRAME(x) (0x55 + (x)) /* 0x55 - 0x6f */ +#define ADV7511_REG_AUDIO_INFOFRAME_VERSION 0x70 +#define ADV7511_REG_AUDIO_INFOFRAME_LENGTH 0x71 +#define ADV7511_REG_AUDIO_INFOFRAME_CHECKSUM 0x72 +#define ADV7511_REG_AUDIO_INFOFRAME(x) (0x73 + (x)) /* 0x73 - 0x7c */ +#define ADV7511_REG_INT_ENABLE(x) (0x94 + (x)) +#define ADV7511_REG_INT(x) (0x96 + (x)) +#define ADV7511_REG_INPUT_CLK_DIV 0x9d +#define ADV7511_REG_PLL_STATUS 0x9e +#define ADV7511_REG_HDMI_POWER 0xa1 +#define ADV7511_REG_HDCP_HDMI_CFG 0xaf +#define ADV7511_REG_AN(x) (0xb0 + (x)) /* 0xb0 - 0xb7 */ +#define ADV7511_REG_HDCP_STATUS 0xb8 +#define ADV7511_REG_BCAPS 0xbe +#define ADV7511_REG_BKSV(x) (0xc0 + (x)) /* 0xc0 - 0xc3 */ +#define ADV7511_REG_EDID_SEGMENT 0xc4 +#define ADV7511_REG_DDC_STATUS 0xc8 +#define ADV7511_REG_EDID_READ_CTRL 0xc9 +#define ADV7511_REG_BSTATUS(x) (0xca + (x)) /* 0xca - 0xcb */ +#define ADV7511_REG_TIMING_GEN_SEQ 0xd0 +#define ADV7511_REG_POWER2 0xd6 +#define ADV7511_REG_HSYNC_PLACEMENT_MSB 0xfa + +#define ADV7511_REG_SYNC_ADJUSTMENT(x) (0xd7 + (x)) /* 0xd7 - 0xdc */ +#define ADV7511_REG_TMDS_CLOCK_INV 0xde +#define ADV7511_REG_ARC_CTRL 0xdf +#define ADV7511_REG_CEC_I2C_ADDR 0xe1 +#define ADV7511_REG_CEC_CTRL 0xe2 +#define ADV7511_REG_CHIP_ID_HIGH 0xf5 +#define ADV7511_REG_CHIP_ID_LOW 0xf6 + +#define ADV7511_CSC_ENABLE BIT(7) +#define ADV7511_CSC_UPDATE_MODE BIT(5) + +#define ADV7511_INT0_HDP BIT(7) +#define ADV7511_INT0_VSYNC BIT(5) +#define ADV7511_INT0_AUDIO_FIFO_FULL BIT(4) +#define ADV7511_INT0_EDID_READY BIT(2) +#define ADV7511_INT0_HDCP_AUTHENTICATED BIT(1) + +#define ADV7511_INT1_DDC_ERROR BIT(7) +#define ADV7511_INT1_BKSV BIT(6) +#define ADV7511_INT1_CEC_TX_READY BIT(5) +#define ADV7511_INT1_CEC_TX_ARBIT_LOST BIT(4) +#define ADV7511_INT1_CEC_TX_RETRY_TIMEOUT BIT(3) +#define ADV7511_INT1_CEC_RX_READY3 BIT(2) +#define ADV7511_INT1_CEC_RX_READY2 BIT(1) +#define ADV7511_INT1_CEC_RX_READY1 BIT(0) + +#define ADV7511_ARC_CTRL_POWER_DOWN BIT(0) + +#define ADV7511_CEC_CTRL_POWER_DOWN BIT(0) + +#define ADV7511_POWER_POWER_DOWN BIT(6) + +#define ADV7511_HDMI_CFG_MODE_MASK 0x2 +#define ADV7511_HDMI_CFG_MODE_DVI 0x0 +#define ADV7511_HDMI_CFG_MODE_HDMI 0x2 + +#define ADV7511_AUDIO_SELECT_I2C 0x0 +#define ADV7511_AUDIO_SELECT_SPDIF 0x1 +#define ADV7511_AUDIO_SELECT_DSD 0x2 +#define ADV7511_AUDIO_SELECT_HBR 0x3 +#define ADV7511_AUDIO_SELECT_DST 0x4 + +#define ADV7511_I2S_SAMPLE_LEN_16 0x2 +#define ADV7511_I2S_SAMPLE_LEN_20 0x3 +#define ADV7511_I2S_SAMPLE_LEN_18 0x4 +#define ADV7511_I2S_SAMPLE_LEN_22 0x5 +#define ADV7511_I2S_SAMPLE_LEN_19 0x8 +#define ADV7511_I2S_SAMPLE_LEN_23 0x9 +#define ADV7511_I2S_SAMPLE_LEN_24 0xb +#define ADV7511_I2S_SAMPLE_LEN_17 0xc +#define ADV7511_I2S_SAMPLE_LEN_21 0xd + +#define ADV7511_SAMPLE_FREQ_44100 0x0 +#define ADV7511_SAMPLE_FREQ_48000 0x2 +#define ADV7511_SAMPLE_FREQ_32000 0x3 +#define ADV7511_SAMPLE_FREQ_88200 0x8 +#define ADV7511_SAMPLE_FREQ_96000 0xa +#define ADV7511_SAMPLE_FREQ_176400 0xc +#define ADV7511_SAMPLE_FREQ_192000 0xe + +#define ADV7511_STATUS_POWER_DOWN_POLARITY BIT(7) +#define ADV7511_STATUS_HPD BIT(6) +#define ADV7511_STATUS_MONITOR_SENSE BIT(5) +#define ADV7511_STATUS_I2S_32BIT_MODE BIT(3) + +#define ADV7511_PACKET_ENABLE_N_CTS BIT(8+6) +#define ADV7511_PACKET_ENABLE_AUDIO_SAMPLE BIT(8+5) +#define ADV7511_PACKET_ENABLE_AVI_INFOFRAME BIT(8+4) +#define ADV7511_PACKET_ENABLE_AUDIO_INFOFRAME BIT(8+3) +#define ADV7511_PACKET_ENABLE_GC BIT(7) +#define ADV7511_PACKET_ENABLE_SPD BIT(6) +#define ADV7511_PACKET_ENABLE_MPEG BIT(5) +#define ADV7511_PACKET_ENABLE_ACP BIT(4) +#define ADV7511_PACKET_ENABLE_ISRC BIT(3) +#define ADV7511_PACKET_ENABLE_GM BIT(2) +#define ADV7511_PACKET_ENABLE_SPARE2 BIT(1) +#define ADV7511_PACKET_ENABLE_SPARE1 BIT(0) + +#define ADV7511_REG_POWER2_HDP_SRC_MASK 0xc0 +#define ADV7511_REG_POWER2_HDP_SRC_BOTH 0x00 +#define ADV7511_REG_POWER2_HDP_SRC_HDP 0x40 +#define ADV7511_REG_POWER2_HDP_SRC_CEC 0x80 +#define ADV7511_REG_POWER2_HDP_SRC_NONE 0xc0 +#define ADV7511_REG_POWER2_TDMS_ENABLE BIT(4) +#define ADV7511_REG_POWER2_GATE_INPUT_CLK BIT(0) + +#define ADV7511_LOW_REFRESH_RATE_NONE 0x0 +#define ADV7511_LOW_REFRESH_RATE_24HZ 0x1 +#define ADV7511_LOW_REFRESH_RATE_25HZ 0x2 +#define ADV7511_LOW_REFRESH_RATE_30HZ 0x3 + +#define ADV7511_AUDIO_CFG3_LEN_MASK 0x0f +#define ADV7511_I2C_FREQ_ID_CFG_RATE_MASK 0xf0 + +#define ADV7511_AUDIO_SOURCE_I2S 0 +#define ADV7511_AUDIO_SOURCE_SPDIF 1 + +#define ADV7511_I2S_FORMAT_I2S 0 +#define ADV7511_I2S_FORMAT_RIGHT_J 1 +#define ADV7511_I2S_FORMAT_LEFT_J 2 + +#define ADV7511_PACKET(p, x) ((p) * 0x20 + (x)) +#define ADV7511_PACKET_SDP(x) ADV7511_PACKET(0, x) +#define ADV7511_PACKET_MPEG(x) ADV7511_PACKET(1, x) +#define ADV7511_PACKET_ACP(x) ADV7511_PACKET(2, x) +#define ADV7511_PACKET_ISRC1(x) ADV7511_PACKET(3, x) +#define ADV7511_PACKET_ISRC2(x) ADV7511_PACKET(4, x) +#define ADV7511_PACKET_GM(x) ADV7511_PACKET(5, x) +#define ADV7511_PACKET_SPARE(x) ADV7511_PACKET(6, x) + +enum adv7511_input_clock { + ADV7511_INPUT_CLOCK_1X, + ADV7511_INPUT_CLOCK_2X, + ADV7511_INPUT_CLOCK_DDR, +}; + +enum adv7511_input_justification { + ADV7511_INPUT_JUSTIFICATION_EVENLY = 0, + ADV7511_INPUT_JUSTIFICATION_RIGHT = 1, + ADV7511_INPUT_JUSTIFICATION_LEFT = 2, +}; + +enum adv7511_input_sync_pulse { + ADV7511_INPUT_SYNC_PULSE_DE = 0, + ADV7511_INPUT_SYNC_PULSE_HSYNC = 1, + ADV7511_INPUT_SYNC_PULSE_VSYNC = 2, + ADV7511_INPUT_SYNC_PULSE_NONE = 3, +}; + +/** + * enum adv7511_sync_polarity - Polarity for the input sync signals + * @ADV7511_SYNC_POLARITY_PASSTHROUGH: Sync polarity matches that of + * the currently configured mode. + * @ADV7511_SYNC_POLARITY_LOW: Sync polarity is low + * @ADV7511_SYNC_POLARITY_HIGH: Sync polarity is high + * + * If the polarity is set to either LOW or HIGH the driver will configure the + * ADV7511 to internally invert the sync signal if required to match the sync + * polarity setting for the currently selected output mode. + * + * If the polarity is set to PASSTHROUGH, the ADV7511 will route the signal + * unchanged. This is used when the upstream graphics core already generates + * the sync signals with the correct polarity. + */ +enum adv7511_sync_polarity { + ADV7511_SYNC_POLARITY_PASSTHROUGH, + ADV7511_SYNC_POLARITY_LOW, + ADV7511_SYNC_POLARITY_HIGH, +}; + +/** + * struct adv7511_link_config - Describes adv7511 hardware configuration + * @input_color_depth: Number of bits per color component (8, 10 or 12) + * @input_colorspace: The input colorspace (RGB, YUV444, YUV422) + * @input_clock: The input video clock style (1x, 2x, DDR) + * @input_style: The input component arrangement variant + * @input_justification: Video input format bit justification + * @clock_delay: Clock delay for the input clock (in ps) + * @embedded_sync: Video input uses BT.656-style embedded sync + * @sync_pulse: Select the sync pulse + * @vsync_polarity: vsync input signal configuration + * @hsync_polarity: hsync input signal configuration + */ +struct adv7511_link_config { + unsigned int input_color_depth; + enum hdmi_colorspace input_colorspace; + enum adv7511_input_clock input_clock; + unsigned int input_style; + enum adv7511_input_justification input_justification; + + int clock_delay; + + bool embedded_sync; + enum adv7511_input_sync_pulse sync_pulse; + enum adv7511_sync_polarity vsync_polarity; + enum adv7511_sync_polarity hsync_polarity; +}; + +/** + * enum adv7511_csc_scaling - Scaling factor for the ADV7511 CSC + * @ADV7511_CSC_SCALING_1: CSC results are not scaled + * @ADV7511_CSC_SCALING_2: CSC results are scaled by a factor of two + * @ADV7511_CSC_SCALING_4: CSC results are scalled by a factor of four + */ +enum adv7511_csc_scaling { + ADV7511_CSC_SCALING_1 = 0, + ADV7511_CSC_SCALING_2 = 1, + ADV7511_CSC_SCALING_4 = 2, +}; + +/** + * struct adv7511_video_config - Describes adv7511 hardware configuration + * @csc_enable: Whether to enable color space conversion + * @csc_scaling_factor: Color space conversion scaling factor + * @csc_coefficents: Color space conversion coefficents + * @hdmi_mode: Whether to use HDMI or DVI output mode + * @avi_infoframe: HDMI infoframe + */ +struct adv7511_video_config { + bool csc_enable; + enum adv7511_csc_scaling csc_scaling_factor; + const uint16_t *csc_coefficents; + + bool hdmi_mode; + struct hdmi_avi_infoframe avi_infoframe; +}; + +#endif /* __DRM_I2C_ADV7511_H__ */ diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig index c96f6089f8bf..2324a526de65 100644 --- a/drivers/gpu/drm/rcar-du/Kconfig +++ b/drivers/gpu/drm/rcar-du/Kconfig @@ -11,10 +11,17 @@ config DRM_RCAR_DU Choose this option if you have an R-Car chipset. If M is selected the module will be called rcar-du-drm. +config DRM_RCAR_HDMI + bool "R-Car DU HDMI Encoder Support" + depends on DRM_RCAR_DU + depends on OF + help + Enable support for external HDMI encoders. + config DRM_RCAR_LVDS bool "R-Car DU LVDS Encoder Support" depends on DRM_RCAR_DU depends on ARCH_R8A7790 || ARCH_R8A7791 || COMPILE_TEST help - Enable support the R-Car Display Unit embedded LVDS encoders - (currently only on R8A7790). + Enable support for the R-Car Display Unit embedded LVDS encoders + (currently only on R8A7790 and R8A7791). diff --git a/drivers/gpu/drm/rcar-du/Makefile b/drivers/gpu/drm/rcar-du/Makefile index 12b8d4477835..05de1c4097af 100644 --- a/drivers/gpu/drm/rcar-du/Makefile +++ b/drivers/gpu/drm/rcar-du/Makefile @@ -7,6 +7,8 @@ rcar-du-drm-y := rcar_du_crtc.o \ rcar_du_plane.o \ rcar_du_vgacon.o +rcar-du-drm-$(CONFIG_DRM_RCAR_HDMI) += rcar_du_hdmicon.o \ + rcar_du_hdmienc.o rcar-du-drm-$(CONFIG_DRM_RCAR_LVDS) += rcar_du_lvdsenc.o obj-$(CONFIG_DRM_RCAR_DU) += rcar-du-drm.o diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 088bfd875d29..23cc910951f4 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -586,7 +586,7 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index) if (irq < 0) { dev_err(rcdu->dev, "no IRQ for CRTC %u\n", index); - return ret; + return irq; } ret = devm_request_irq(rcdu->dev, irq, rcar_du_crtc_irq, irqflags, diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h index e97ae502dec5..984e6083699f 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h @@ -15,7 +15,6 @@ #define __RCAR_DU_CRTC_H__ #include -#include #include #include @@ -41,6 +40,15 @@ struct rcar_du_crtc { #define to_rcar_crtc(c) container_of(c, struct rcar_du_crtc, crtc) +enum rcar_du_output { + RCAR_DU_OUTPUT_DPAD0, + RCAR_DU_OUTPUT_DPAD1, + RCAR_DU_OUTPUT_LVDS0, + RCAR_DU_OUTPUT_LVDS1, + RCAR_DU_OUTPUT_TCON, + RCAR_DU_OUTPUT_MAX, +}; + int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index); void rcar_du_crtc_enable_vblank(struct rcar_du_crtc *rcrtc, bool enable); void rcar_du_crtc_cancel_page_flip(struct rcar_du_crtc *rcrtc, diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index d212efa6a495..967ae8f20233 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c @@ -146,12 +146,11 @@ static int rcar_du_load(struct drm_device *dev, unsigned long flags) { struct platform_device *pdev = dev->platformdev; struct device_node *np = pdev->dev.of_node; - struct rcar_du_platform_data *pdata = pdev->dev.platform_data; struct rcar_du_device *rcdu; struct resource *mem; int ret; - if (pdata == NULL && np == NULL) { + if (np == NULL) { dev_err(dev->dev, "no platform data\n"); return -ENODEV; } @@ -163,7 +162,6 @@ static int rcar_du_load(struct drm_device *dev, unsigned long flags) } rcdu->dev = &pdev->dev; - rcdu->pdata = pdata; rcdu->info = np ? of_match_device(rcar_du_of_table, rcdu->dev)->data : (void *)platform_get_device_id(pdev)->driver_data; rcdu->ddev = dev; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h index 8e494633c3b3..0a724669f02d 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h @@ -15,7 +15,6 @@ #define __RCAR_DU_DRV_H__ #include -#include #include "rcar_du_crtc.h" #include "rcar_du_group.h" @@ -67,7 +66,6 @@ struct rcar_du_device_info { struct rcar_du_device { struct device *dev; - const struct rcar_du_platform_data *pdata; const struct rcar_du_device_info *info; void __iomem *mmio; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c index 7c0ec95915ef..34a122a39664 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c @@ -19,6 +19,8 @@ #include "rcar_du_drv.h" #include "rcar_du_encoder.h" +#include "rcar_du_hdmicon.h" +#include "rcar_du_hdmienc.h" #include "rcar_du_kms.h" #include "rcar_du_lvdscon.h" #include "rcar_du_lvdsenc.h" @@ -33,7 +35,7 @@ rcar_du_connector_best_encoder(struct drm_connector *connector) { struct rcar_du_connector *rcon = to_rcar_connector(connector); - return &rcon->encoder->encoder; + return rcar_encoder_to_drm_encoder(rcon->encoder); } /* ----------------------------------------------------------------------------- @@ -142,10 +144,11 @@ static const struct drm_encoder_funcs encoder_funcs = { int rcar_du_encoder_init(struct rcar_du_device *rcdu, enum rcar_du_encoder_type type, enum rcar_du_output output, - const struct rcar_du_encoder_data *data, - struct device_node *np) + struct device_node *enc_node, + struct device_node *con_node) { struct rcar_du_encoder *renc; + struct drm_encoder *encoder; unsigned int encoder_type; int ret; @@ -154,6 +157,7 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu, return -ENOMEM; renc->output = output; + encoder = rcar_encoder_to_drm_encoder(renc); switch (output) { case RCAR_DU_OUTPUT_LVDS0: @@ -175,6 +179,9 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu, case RCAR_DU_ENCODER_LVDS: encoder_type = DRM_MODE_ENCODER_LVDS; break; + case RCAR_DU_ENCODER_HDMI: + encoder_type = DRM_MODE_ENCODER_TMDS; + break; case RCAR_DU_ENCODER_NONE: default: /* No external encoder, use the internal encoder type. */ @@ -182,23 +189,35 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu, break; } - ret = drm_encoder_init(rcdu->ddev, &renc->encoder, &encoder_funcs, - encoder_type); - if (ret < 0) - return ret; + if (type == RCAR_DU_ENCODER_HDMI) { + if (renc->lvds) { + dev_err(rcdu->dev, + "Chaining LVDS and HDMI encoders not supported\n"); + return -EINVAL; + } - drm_encoder_helper_add(&renc->encoder, &encoder_helper_funcs); + ret = rcar_du_hdmienc_init(rcdu, renc, enc_node); + if (ret < 0) + return ret; + } else { + ret = drm_encoder_init(rcdu->ddev, encoder, &encoder_funcs, + encoder_type); + if (ret < 0) + return ret; + + drm_encoder_helper_add(encoder, &encoder_helper_funcs); + } switch (encoder_type) { - case DRM_MODE_ENCODER_LVDS: { - const struct rcar_du_panel_data *pdata = - data ? &data->connector.lvds.panel : NULL; - return rcar_du_lvds_connector_init(rcdu, renc, pdata, np); - } + case DRM_MODE_ENCODER_LVDS: + return rcar_du_lvds_connector_init(rcdu, renc, con_node); case DRM_MODE_ENCODER_DAC: return rcar_du_vga_connector_init(rcdu, renc); + case DRM_MODE_ENCODER_TMDS: + return rcar_du_hdmi_connector_init(rcdu, renc); + default: return -EINVAL; } diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.h b/drivers/gpu/drm/rcar-du/rcar_du_encoder.h index bd624135ef1f..719b6f2a031c 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.h @@ -14,21 +14,32 @@ #ifndef __RCAR_DU_ENCODER_H__ #define __RCAR_DU_ENCODER_H__ -#include - #include +#include struct rcar_du_device; +struct rcar_du_hdmienc; struct rcar_du_lvdsenc; +enum rcar_du_encoder_type { + RCAR_DU_ENCODER_UNUSED = 0, + RCAR_DU_ENCODER_NONE, + RCAR_DU_ENCODER_VGA, + RCAR_DU_ENCODER_LVDS, + RCAR_DU_ENCODER_HDMI, +}; + struct rcar_du_encoder { - struct drm_encoder encoder; + struct drm_encoder_slave slave; enum rcar_du_output output; + struct rcar_du_hdmienc *hdmi; struct rcar_du_lvdsenc *lvds; }; #define to_rcar_encoder(e) \ - container_of(e, struct rcar_du_encoder, encoder) + container_of(e, struct rcar_du_encoder, slave.base) + +#define rcar_encoder_to_drm_encoder(e) (&(e)->slave.base) struct rcar_du_connector { struct drm_connector connector; @@ -44,7 +55,7 @@ rcar_du_connector_best_encoder(struct drm_connector *connector); int rcar_du_encoder_init(struct rcar_du_device *rcdu, enum rcar_du_encoder_type type, enum rcar_du_output output, - const struct rcar_du_encoder_data *data, - struct device_node *np); + struct device_node *enc_node, + struct device_node *con_node); #endif /* __RCAR_DU_ENCODER_H__ */ diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c b/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c new file mode 100644 index 000000000000..8abaaf258f45 --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c @@ -0,0 +1,118 @@ +/* + * R-Car Display Unit HDMI Connector + * + * Copyright (C) 2014 Renesas Electronics Corporation + * + * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include + +#include "rcar_du_drv.h" +#include "rcar_du_encoder.h" +#include "rcar_du_hdmicon.h" +#include "rcar_du_kms.h" + +#define to_slave_funcs(e) (to_rcar_encoder(e)->slave.slave_funcs) + +static int rcar_du_hdmi_connector_get_modes(struct drm_connector *connector) +{ + struct drm_encoder *encoder = connector->encoder; + struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder); + + if (sfuncs->get_modes == NULL) + return 0; + + return sfuncs->get_modes(encoder, connector); +} + +static int rcar_du_hdmi_connector_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + struct drm_encoder *encoder = connector->encoder; + struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder); + + if (sfuncs->mode_valid == NULL) + return MODE_OK; + + return sfuncs->mode_valid(encoder, mode); +} + +static const struct drm_connector_helper_funcs connector_helper_funcs = { + .get_modes = rcar_du_hdmi_connector_get_modes, + .mode_valid = rcar_du_hdmi_connector_mode_valid, + .best_encoder = rcar_du_connector_best_encoder, +}; + +static void rcar_du_hdmi_connector_destroy(struct drm_connector *connector) +{ + drm_connector_unregister(connector); + drm_connector_cleanup(connector); +} + +static enum drm_connector_status +rcar_du_hdmi_connector_detect(struct drm_connector *connector, bool force) +{ + struct drm_encoder *encoder = connector->encoder; + struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder); + + if (sfuncs->detect == NULL) + return connector_status_unknown; + + return sfuncs->detect(encoder, connector); +} + +static const struct drm_connector_funcs connector_funcs = { + .dpms = drm_helper_connector_dpms, + .detect = rcar_du_hdmi_connector_detect, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = rcar_du_hdmi_connector_destroy, +}; + +int rcar_du_hdmi_connector_init(struct rcar_du_device *rcdu, + struct rcar_du_encoder *renc) +{ + struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(renc); + struct rcar_du_connector *rcon; + struct drm_connector *connector; + int ret; + + rcon = devm_kzalloc(rcdu->dev, sizeof(*rcon), GFP_KERNEL); + if (rcon == NULL) + return -ENOMEM; + + connector = &rcon->connector; + connector->display_info.width_mm = 0; + connector->display_info.height_mm = 0; + + ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs, + DRM_MODE_CONNECTOR_HDMIA); + if (ret < 0) + return ret; + + drm_connector_helper_add(connector, &connector_helper_funcs); + ret = drm_connector_register(connector); + if (ret < 0) + return ret; + + drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); + drm_object_property_set_value(&connector->base, + rcdu->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF); + + ret = drm_mode_connector_attach_encoder(connector, encoder); + if (ret < 0) + return ret; + + connector->encoder = encoder; + rcon->encoder = renc; + + return 0; +} diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.h b/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.h new file mode 100644 index 000000000000..87daa949227f --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.h @@ -0,0 +1,31 @@ +/* + * R-Car Display Unit HDMI Connector + * + * Copyright (C) 2014 Renesas Electronics Corporation + * + * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __RCAR_DU_HDMICON_H__ +#define __RCAR_DU_HDMICON_H__ + +struct rcar_du_device; +struct rcar_du_encoder; + +#if IS_ENABLED(CONFIG_DRM_RCAR_HDMI) +int rcar_du_hdmi_connector_init(struct rcar_du_device *rcdu, + struct rcar_du_encoder *renc); +#else +static inline int rcar_du_hdmi_connector_init(struct rcar_du_device *rcdu, + struct rcar_du_encoder *renc) +{ + return -ENOSYS; +} +#endif + +#endif /* __RCAR_DU_HDMICON_H__ */ diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c new file mode 100644 index 000000000000..359bc999a9c8 --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c @@ -0,0 +1,151 @@ +/* + * R-Car Display Unit HDMI Encoder + * + * Copyright (C) 2014 Renesas Electronics Corporation + * + * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include + +#include +#include +#include +#include + +#include "rcar_du_drv.h" +#include "rcar_du_encoder.h" +#include "rcar_du_hdmienc.h" + +struct rcar_du_hdmienc { + struct rcar_du_encoder *renc; + struct device *dev; + int dpms; +}; + +#define to_rcar_hdmienc(e) (to_rcar_encoder(e)->hdmi) +#define to_slave_funcs(e) (to_rcar_encoder(e)->slave.slave_funcs) + +static void rcar_du_hdmienc_dpms(struct drm_encoder *encoder, int mode) +{ + struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder); + struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder); + + if (hdmienc->dpms == mode) + return; + + if (sfuncs->dpms) + sfuncs->dpms(encoder, mode); + + hdmienc->dpms = mode; +} + +static bool rcar_du_hdmienc_mode_fixup(struct drm_encoder *encoder, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder); + + if (sfuncs->mode_fixup == NULL) + return true; + + return sfuncs->mode_fixup(encoder, mode, adjusted_mode); +} + +static void rcar_du_hdmienc_mode_prepare(struct drm_encoder *encoder) +{ + rcar_du_hdmienc_dpms(encoder, DRM_MODE_DPMS_OFF); +} + +static void rcar_du_hdmienc_mode_commit(struct drm_encoder *encoder) +{ + rcar_du_hdmienc_dpms(encoder, DRM_MODE_DPMS_ON); +} + +static void rcar_du_hdmienc_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder); + struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder); + + if (sfuncs->mode_set) + sfuncs->mode_set(encoder, mode, adjusted_mode); + + rcar_du_crtc_route_output(encoder->crtc, hdmienc->renc->output); +} + +static const struct drm_encoder_helper_funcs encoder_helper_funcs = { + .dpms = rcar_du_hdmienc_dpms, + .mode_fixup = rcar_du_hdmienc_mode_fixup, + .prepare = rcar_du_hdmienc_mode_prepare, + .commit = rcar_du_hdmienc_mode_commit, + .mode_set = rcar_du_hdmienc_mode_set, +}; + +static void rcar_du_hdmienc_cleanup(struct drm_encoder *encoder) +{ + struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder); + + rcar_du_hdmienc_dpms(encoder, DRM_MODE_DPMS_OFF); + + drm_encoder_cleanup(encoder); + put_device(hdmienc->dev); +} + +static const struct drm_encoder_funcs encoder_funcs = { + .destroy = rcar_du_hdmienc_cleanup, +}; + +int rcar_du_hdmienc_init(struct rcar_du_device *rcdu, + struct rcar_du_encoder *renc, struct device_node *np) +{ + struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(renc); + struct drm_i2c_encoder_driver *driver; + struct i2c_client *i2c_slave; + struct rcar_du_hdmienc *hdmienc; + int ret; + + hdmienc = devm_kzalloc(rcdu->dev, sizeof(*hdmienc), GFP_KERNEL); + if (hdmienc == NULL) + return -ENOMEM; + + /* Locate the slave I2C device and driver. */ + i2c_slave = of_find_i2c_device_by_node(np); + if (!i2c_slave || !i2c_get_clientdata(i2c_slave)) + return -EPROBE_DEFER; + + hdmienc->dev = &i2c_slave->dev; + + if (hdmienc->dev->driver == NULL) { + ret = -EPROBE_DEFER; + goto error; + } + + /* Initialize the slave encoder. */ + driver = to_drm_i2c_encoder_driver(to_i2c_driver(hdmienc->dev->driver)); + ret = driver->encoder_init(i2c_slave, rcdu->ddev, &renc->slave); + if (ret < 0) + goto error; + + ret = drm_encoder_init(rcdu->ddev, encoder, &encoder_funcs, + DRM_MODE_ENCODER_TMDS); + if (ret < 0) + goto error; + + drm_encoder_helper_add(encoder, &encoder_helper_funcs); + + renc->hdmi = hdmienc; + hdmienc->renc = renc; + + return 0; + +error: + put_device(hdmienc->dev); + return ret; +} diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.h b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.h new file mode 100644 index 000000000000..2ff0128ac8e1 --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.h @@ -0,0 +1,35 @@ +/* + * R-Car Display Unit HDMI Encoder + * + * Copyright (C) 2014 Renesas Electronics Corporation + * + * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __RCAR_DU_HDMIENC_H__ +#define __RCAR_DU_HDMIENC_H__ + +#include + +struct device_node; +struct rcar_du_device; +struct rcar_du_encoder; + +#if IS_ENABLED(CONFIG_DRM_RCAR_HDMI) +int rcar_du_hdmienc_init(struct rcar_du_device *rcdu, + struct rcar_du_encoder *renc, struct device_node *np); +#else +static inline int rcar_du_hdmienc_init(struct rcar_du_device *rcdu, + struct rcar_du_encoder *renc, + struct device_node *np) +{ + return -ENOSYS; +} +#endif + +#endif /* __RCAR_DU_HDMIENC_H__ */ diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c index 6289e3797bc5..0c5ee616b5a3 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c @@ -190,49 +190,16 @@ static const struct drm_mode_config_funcs rcar_du_mode_config_funcs = { .output_poll_changed = rcar_du_output_poll_changed, }; -static int rcar_du_encoders_init_pdata(struct rcar_du_device *rcdu) -{ - unsigned int num_encoders = 0; - unsigned int i; - int ret; - - for (i = 0; i < rcdu->pdata->num_encoders; ++i) { - const struct rcar_du_encoder_data *pdata = - &rcdu->pdata->encoders[i]; - const struct rcar_du_output_routing *route = - &rcdu->info->routes[pdata->output]; - - if (pdata->type == RCAR_DU_ENCODER_UNUSED) - continue; - - if (pdata->output >= RCAR_DU_OUTPUT_MAX || - route->possible_crtcs == 0) { - dev_warn(rcdu->dev, - "encoder %u references unexisting output %u, skipping\n", - i, pdata->output); - continue; - } - - ret = rcar_du_encoder_init(rcdu, pdata->type, pdata->output, - pdata, NULL); - if (ret < 0) - return ret; - - num_encoders++; - } - - return num_encoders; -} - -static int rcar_du_encoders_init_dt_one(struct rcar_du_device *rcdu, - enum rcar_du_output output, - struct of_endpoint *ep) +static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu, + enum rcar_du_output output, + struct of_endpoint *ep) { static const struct { const char *compatible; enum rcar_du_encoder_type type; } encoders[] = { { "adi,adv7123", RCAR_DU_ENCODER_VGA }, + { "adi,adv7511w", RCAR_DU_ENCODER_HDMI }, { "thine,thc63lvdm83d", RCAR_DU_ENCODER_LVDS }, }; @@ -323,14 +290,14 @@ static int rcar_du_encoders_init_dt_one(struct rcar_du_device *rcdu, connector = entity; } - ret = rcar_du_encoder_init(rcdu, enc_type, output, NULL, connector); + ret = rcar_du_encoder_init(rcdu, enc_type, output, encoder, connector); of_node_put(encoder); of_node_put(connector); return ret < 0 ? ret : 1; } -static int rcar_du_encoders_init_dt(struct rcar_du_device *rcdu) +static int rcar_du_encoders_init(struct rcar_du_device *rcdu) { struct device_node *np = rcdu->dev->of_node; struct device_node *prev = NULL; @@ -377,7 +344,7 @@ static int rcar_du_encoders_init_dt(struct rcar_du_device *rcdu) } /* Process the output pipeline. */ - ret = rcar_du_encoders_init_dt_one(rcdu, output, &ep); + ret = rcar_du_encoders_init_one(rcdu, output, &ep); if (ret < 0) { of_node_put(ep_node); return ret; @@ -442,11 +409,7 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu) if (ret < 0) return ret; - if (rcdu->pdata) - ret = rcar_du_encoders_init_pdata(rcdu); - else - ret = rcar_du_encoders_init_dt(rcdu); - + ret = rcar_du_encoders_init(rcdu); if (ret < 0) return ret; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c b/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c index 115eed20db12..6d9811c052c4 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.c @@ -27,7 +27,11 @@ struct rcar_du_lvds_connector { struct rcar_du_connector connector; - struct rcar_du_panel_data panel; + struct { + unsigned int width_mm; /* Panel width in mm */ + unsigned int height_mm; /* Panel height in mm */ + struct videomode mode; + } panel; }; #define to_rcar_lvds_connector(c) \ @@ -78,31 +82,26 @@ static const struct drm_connector_funcs connector_funcs = { int rcar_du_lvds_connector_init(struct rcar_du_device *rcdu, struct rcar_du_encoder *renc, - const struct rcar_du_panel_data *panel, /* TODO const */ struct device_node *np) { + struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(renc); struct rcar_du_lvds_connector *lvdscon; struct drm_connector *connector; + struct display_timing timing; int ret; lvdscon = devm_kzalloc(rcdu->dev, sizeof(*lvdscon), GFP_KERNEL); if (lvdscon == NULL) return -ENOMEM; - if (panel) { - lvdscon->panel = *panel; - } else { - struct display_timing timing; + ret = of_get_display_timing(np, "panel-timing", &timing); + if (ret < 0) + return ret; - ret = of_get_display_timing(np, "panel-timing", &timing); - if (ret < 0) - return ret; + videomode_from_timing(&timing, &lvdscon->panel.mode); - videomode_from_timing(&timing, &lvdscon->panel.mode); - - of_property_read_u32(np, "width-mm", &lvdscon->panel.width_mm); - of_property_read_u32(np, "height-mm", &lvdscon->panel.height_mm); - } + of_property_read_u32(np, "width-mm", &lvdscon->panel.width_mm); + of_property_read_u32(np, "height-mm", &lvdscon->panel.height_mm); connector = &lvdscon->connector.connector; connector->display_info.width_mm = lvdscon->panel.width_mm; @@ -122,11 +121,11 @@ int rcar_du_lvds_connector_init(struct rcar_du_device *rcdu, drm_object_property_set_value(&connector->base, rcdu->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF); - ret = drm_mode_connector_attach_encoder(connector, &renc->encoder); + ret = drm_mode_connector_attach_encoder(connector, encoder); if (ret < 0) return ret; - connector->encoder = &renc->encoder; + connector->encoder = encoder; lvdscon->connector.encoder = renc; return 0; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.h b/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.h index d11424d537f9..d4881ee0be7e 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_lvdscon.h @@ -16,11 +16,9 @@ struct rcar_du_device; struct rcar_du_encoder; -struct rcar_du_panel_data; int rcar_du_lvds_connector_init(struct rcar_du_device *rcdu, struct rcar_du_encoder *renc, - const struct rcar_du_panel_data *panel, struct device_node *np); #endif /* __RCAR_DU_LVDSCON_H__ */ diff --git a/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.h b/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.h index 3303a55cec79..f65aabda0796 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.h @@ -16,7 +16,6 @@ #include #include -#include struct rcar_drm_crtc; struct rcar_du_lvdsenc; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c b/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c index 564a723ede03..752747a5e920 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c @@ -52,6 +52,7 @@ static const struct drm_connector_funcs connector_funcs = { int rcar_du_vga_connector_init(struct rcar_du_device *rcdu, struct rcar_du_encoder *renc) { + struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(renc); struct rcar_du_connector *rcon; struct drm_connector *connector; int ret; @@ -78,11 +79,11 @@ int rcar_du_vga_connector_init(struct rcar_du_device *rcdu, drm_object_property_set_value(&connector->base, rcdu->ddev->mode_config.dpms_property, DRM_MODE_DPMS_OFF); - ret = drm_mode_connector_attach_encoder(connector, &renc->encoder); + ret = drm_mode_connector_attach_encoder(connector, encoder); if (ret < 0) return ret; - connector->encoder = &renc->encoder; + connector->encoder = encoder; rcon->encoder = renc; return 0; diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index c2f1bfa22010..d59240ffb1f7 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -381,4 +381,9 @@ static inline int drm_eld_size(const uint8_t *eld) return DRM_ELD_HEADER_BLOCK_SIZE + eld[DRM_ELD_BASELINE_ELD_LEN] * 4; } +struct edid *drm_do_get_edid(struct drm_connector *connector, + int (*get_edid_block)(void *data, u8 *buf, unsigned int block, + size_t len), + void *data); + #endif /* __DRM_EDID_H__ */ diff --git a/include/linux/platform_data/rcar-du.h b/include/linux/platform_data/rcar-du.h deleted file mode 100644 index a5f045e1d8fe..000000000000 --- a/include/linux/platform_data/rcar-du.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * rcar_du.h -- R-Car Display Unit DRM driver - * - * Copyright (C) 2013 Renesas Corporation - * - * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#ifndef __RCAR_DU_H__ -#define __RCAR_DU_H__ - -#include