aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2014-08-04 19:28:37 -0400
committerDave Airlie <airlied@redhat.com>2014-08-04 19:28:37 -0400
commit96b1b9711031a1e95e3cf15d830802aed38479a6 (patch)
tree8bfb6b5c7967513453fec422d15c940654eba256
parent920f946428b70494eb1c64e0de260da0d8bde040 (diff)
parent9bbf86fe874cce0169f0e1152d96f0591e680874 (diff)
Merge branch 'drm_kms_for_next-v8' of git://git.linaro.org/people/benjamin.gaignard/kernel into drm-next
This series of patches add the support of DRM/KMS drivers for STMicroelectronics chipsets stih416 and stih407. Hardware is split in two main blocks: Compositor and TVout. Each of them includes specific hardware IPs and the display timing are controlled by a specific Video Timing Generator hardware IP (VTG). Compositor is made of the follow hardware IPs: - GDP (Generic Display Pipeline) which is an entry point for graphic (RGB) buffers - VDP (Video Diplay Pipeline) which is an entry point for video (YUV) buffers - HQVDP (High Quality Video Display Processor) that supports scaling, deinterlacing and some miscellaneous image quality improvements. It fetches the Video decoded buffers from memory, processes them and pushes them to the Compositor through a HW dedicated bus. - Mixer is responsible of mixing all the entries depending of their respective z-order and layout TVout is divided in 3 parts: - HDMI to generate HDMI signals, depending of chipset version HDMI phy can change. - HDA to generate signals for HD analog TV - VIP to control/switch data path coming from Compositor On stih416 compositor and Tvout are on different dies so a Video Trafic Advance inter-die Communication mechanism (VTAC) is needed. +---------------------------------------------+ +----------------------------------------+ | +-------------------------------+ +----+ | | +----+ +--------------------------+ | | | | | | | | | | | +---------+ +----+ | | | | +----+ +------+ | | | | | | | | | VIP |---->|HDMI| | | | | |GPD +------------->| | | | | | | | | | | | +----+ | | | | +----+ |Mixer |--|-->| | | | | |---|->| switcher| | | | | | | | | | | | | | | | | +----+ | | | | | | | | | | | | | | | |---->|HDA | | | | | +------+ | |VTAC|========>|VTAC| | +---------+ +----+ | | | | | | | | | | | | | | | | Compositor | | | | | | | | TVout | | | +-------------------------------+ | | | | | | +--------------------------+ | | ^ | | | | | | ^ | | | | | | | | | | | | +--------------+ | | | | | | +-------------+ | | | VTG (master) |----->| | | | | |----->| VTG (slave) | | | +--------------+ +----+ | | +----+ +-------------+ | |Digital die | | Analog Die| +---------------------------------------------+ +----------------------------------------+ On stih407 Compositor and Tvout are on the same die +-----------------------------------------------------------------+ | +-------------------------------+ +--------------------------+ | | | | | +---------+ +----+ | | | | +----+ +------+ | | | VIP |---->|HDMI| | | | | |GPD +------------->| | | | | | +----+ | | | | +----+ |Mixer |--|--|->| switcher| | | | | +----+ +-----+ | | | | | | +----+ | | | | |VDP +-->+HQVDP+--->| | | | | |---->|HDA | | | | | +----+ +-----+ +------+ | | +---------+ +----+ | | | | | | | | | | Compositor | | TVout | | | +-------------------------------+ +--------------------------+ | | ^ ^ | | | | | | +--------------+ | | | VTG | | | +--------------+ | |Digital die | +-----------------------------------------------------------------+ In addition of the drivers for the IPs listed before a thin I2C driver (hdmiddc) is used by HDMI driver to retrieve EDID for monitor. To unify interfaces of GDP and VDP we create a "layer" interface called by compositor to control both GPD and VDP. Hardware have memory contraints (alignment, contiguous) so we use CMA drm helpers functions to allocate frame buffer. File naming convention is: - sti_* for IPs drivers - sti_drm_* for drm functions implementation. * 'drm_kms_for_next-v8' of git://git.linaro.org/people/benjamin.gaignard/kernel: drm: sti: Add DRM driver itself drm: sti: add Compositor drm: sti: add Mixer drm: sti: add VID layer drm: sti: add GDP layer drm: sti: add TVOut driver drm: sti: add HDA driver drm: sti: add HDMI driver drm: sti: add VTAC drivers drm: sti: add VTG driver drm: sti: add bindings for DRM driver
-rw-r--r--Documentation/devicetree/bindings/gpu/st,stih4xx.txt189
-rw-r--r--drivers/gpu/drm/Kconfig2
-rw-r--r--drivers/gpu/drm/Makefile1
-rw-r--r--drivers/gpu/drm/sti/Kconfig14
-rw-r--r--drivers/gpu/drm/sti/Makefile21
-rw-r--r--drivers/gpu/drm/sti/NOTES58
-rw-r--r--drivers/gpu/drm/sti/sti_compositor.c279
-rw-r--r--drivers/gpu/drm/sti/sti_compositor.h90
-rw-r--r--drivers/gpu/drm/sti/sti_drm_crtc.c423
-rw-r--r--drivers/gpu/drm/sti/sti_drm_crtc.h22
-rw-r--r--drivers/gpu/drm/sti/sti_drm_drv.c241
-rw-r--r--drivers/gpu/drm/sti/sti_drm_drv.h29
-rw-r--r--drivers/gpu/drm/sti/sti_drm_plane.c195
-rw-r--r--drivers/gpu/drm/sti/sti_drm_plane.h18
-rw-r--r--drivers/gpu/drm/sti/sti_gdp.c549
-rw-r--r--drivers/gpu/drm/sti/sti_gdp.h16
-rw-r--r--drivers/gpu/drm/sti/sti_hda.c794
-rw-r--r--drivers/gpu/drm/sti/sti_hdmi.c810
-rw-r--r--drivers/gpu/drm/sti/sti_hdmi.h88
-rw-r--r--drivers/gpu/drm/sti/sti_hdmi_tx3g0c55phy.c336
-rw-r--r--drivers/gpu/drm/sti/sti_hdmi_tx3g0c55phy.h14
-rw-r--r--drivers/gpu/drm/sti/sti_hdmi_tx3g4c28phy.c211
-rw-r--r--drivers/gpu/drm/sti/sti_hdmi_tx3g4c28phy.h14
-rw-r--r--drivers/gpu/drm/sti/sti_layer.c197
-rw-r--r--drivers/gpu/drm/sti/sti_layer.h123
-rw-r--r--drivers/gpu/drm/sti/sti_mixer.c249
-rw-r--r--drivers/gpu/drm/sti/sti_mixer.h54
-rw-r--r--drivers/gpu/drm/sti/sti_tvout.c648
-rw-r--r--drivers/gpu/drm/sti/sti_vid.c138
-rw-r--r--drivers/gpu/drm/sti/sti_vid.h12
-rw-r--r--drivers/gpu/drm/sti/sti_vtac.c215
-rw-r--r--drivers/gpu/drm/sti/sti_vtg.c366
-rw-r--r--drivers/gpu/drm/sti/sti_vtg.h28
33 files changed, 6444 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/gpu/st,stih4xx.txt b/Documentation/devicetree/bindings/gpu/st,stih4xx.txt
new file mode 100644
index 000000000000..2d150c311a05
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpu/st,stih4xx.txt
@@ -0,0 +1,189 @@
1STMicroelectronics stih4xx platforms
2
3- sti-vtg: video timing generator
4 Required properties:
5 - compatible: "st,vtg"
6 - reg: Physical base address of the IP registers and length of memory mapped region.
7 Optional properties:
8 - interrupts : VTG interrupt number to the CPU.
9 - st,slave: phandle on a slave vtg
10
11- sti-vtac: video timing advanced inter dye communication Rx and TX
12 Required properties:
13 - compatible: "st,vtac-main" or "st,vtac-aux"
14 - reg: Physical base address of the IP registers and length of memory mapped region.
15 - clocks: from common clock binding: handle hardware IP needed clocks, the
16 number of clocks may depend of the SoC type.
17 See ../clocks/clock-bindings.txt for details.
18 - clock-names: names of the clocks listed in clocks property in the same
19 order.
20
21- sti-display-subsystem: Master device for DRM sub-components
22 This device must be the parent of all the sub-components and is responsible
23 of bind them.
24 Required properties:
25 - compatible: "st,sti-display-subsystem"
26 - ranges: to allow probing of subdevices
27
28- sti-compositor: frame compositor engine
29 must be a child of sti-display-subsystem
30 Required properties:
31 - compatible: "st,stih<chip>-compositor"
32 - reg: Physical base address of the IP registers and length of memory mapped region.
33 - clocks: from common clock binding: handle hardware IP needed clocks, the
34 number of clocks may depend of the SoC type.
35 See ../clocks/clock-bindings.txt for details.
36 - clock-names: names of the clocks listed in clocks property in the same
37 order.
38 - resets: resets to be used by the device
39 See ../reset/reset.txt for details.
40 - reset-names: names of the resets listed in resets property in the same
41 order.
42 - st,vtg: phandle(s) on vtg device (main and aux) nodes.
43
44- sti-tvout: video out hardware block
45 must be a child of sti-display-subsystem
46 Required properties:
47 - compatible: "st,stih<chip>-tvout"
48 - reg: Physical base address of the IP registers and length of memory mapped region.
49 - reg-names: names of the mapped memory regions listed in regs property in
50 the same order.
51 - resets: resets to be used by the device
52 See ../reset/reset.txt for details.
53 - reset-names: names of the resets listed in resets property in the same
54 order.
55 - ranges: to allow probing of subdevices
56
57- sti-hdmi: hdmi output block
58 must be a child of sti-tvout
59 Required properties:
60 - compatible: "st,stih<chip>-hdmi";
61 - reg: Physical base address of the IP registers and length of memory mapped region.
62 - reg-names: names of the mapped memory regions listed in regs property in
63 the same order.
64 - interrupts : HDMI interrupt number to the CPU.
65 - interrupt-names: name of the interrupts listed in interrupts property in
66 the same order
67 - clocks: from common clock binding: handle hardware IP needed clocks, the
68 number of clocks may depend of the SoC type.
69 - clock-names: names of the clocks listed in clocks property in the same
70 order.
71 - hdmi,hpd-gpio: gpio id to detect if an hdmi cable is plugged or not.
72
73sti-hda:
74 Required properties:
75 must be a child of sti-tvout
76 - compatible: "st,stih<chip>-hda"
77 - reg: Physical base address of the IP registers and length of memory mapped region.
78 - reg-names: names of the mapped memory regions listed in regs property in
79 the same order.
80 - clocks: from common clock binding: handle hardware IP needed clocks, the
81 number of clocks may depend of the SoC type.
82 See ../clocks/clock-bindings.txt for details.
83 - clock-names: names of the clocks listed in clocks property in the same
84 order.
85
86Example:
87
88/ {
89 ...
90
91 vtg_main_slave: sti-vtg-main-slave@fe85A800 {
92 compatible = "st,vtg";
93 reg = <0xfe85A800 0x300>;
94 interrupts = <GIC_SPI 175 IRQ_TYPE_NONE>;
95 };
96
97 vtg_main: sti-vtg-main-master@fd348000 {
98 compatible = "st,vtg";
99 reg = <0xfd348000 0x400>;
100 st,slave = <&vtg_main_slave>;
101 };
102
103 vtg_aux_slave: sti-vtg-aux-slave@fd348400 {
104 compatible = "st,vtg";
105 reg = <0xfe858200 0x300>;
106 interrupts = <GIC_SPI 176 IRQ_TYPE_NONE>;
107 };
108
109 vtg_aux: sti-vtg-aux-master@fd348400 {
110 compatible = "st,vtg";
111 reg = <0xfd348400 0x400>;
112 st,slave = <&vtg_aux_slave>;
113 };
114
115
116 sti-vtac-rx-main@fee82800 {
117 compatible = "st,vtac-main";
118 reg = <0xfee82800 0x200>;
119 clock-names = "vtac";
120 clocks = <&clk_m_a2_div0 CLK_M_VTAC_MAIN_PHY>;
121 };
122
123 sti-vtac-rx-aux@fee82a00 {
124 compatible = "st,vtac-aux";
125 reg = <0xfee82a00 0x200>;
126 clock-names = "vtac";
127 clocks = <&clk_m_a2_div0 CLK_M_VTAC_AUX_PHY>;
128 };
129
130 sti-vtac-tx-main@fd349000 {
131 compatible = "st,vtac-main";
132 reg = <0xfd349000 0x200>, <0xfd320000 0x10000>;
133 clock-names = "vtac";
134 clocks = <&clk_s_a1_hs CLK_S_VTAC_TX_PHY>;
135 };
136
137 sti-vtac-tx-aux@fd349200 {
138 compatible = "st,vtac-aux";
139 reg = <0xfd349200 0x200>, <0xfd320000 0x10000>;
140 clock-names = "vtac";
141 clocks = <&clk_s_a1_hs CLK_S_VTAC_TX_PHY>;
142 };
143
144 sti-display-subsystem {
145 compatible = "st,sti-display-subsystem";
146 ranges;
147
148 sti-compositor@fd340000 {
149 compatible = "st,stih416-compositor";
150 reg = <0xfd340000 0x1000>;
151 clock-names = "compo_main", "compo_aux",
152 "pix_main", "pix_aux";
153 clocks = <&clk_m_a2_div1 CLK_M_COMPO_MAIN>, <&clk_m_a2_div1 CLK_M_COMPO_AUX>,
154 <&clockgen_c_vcc CLK_S_PIX_MAIN>, <&clockgen_c_vcc CLK_S_PIX_AUX>;
155 reset-names = "compo-main", "compo-aux";
156 resets = <&softreset STIH416_COMPO_M_SOFTRESET>, <&softreset STIH416_COMPO_A_SOFTRESET>;
157 st,vtg = <&vtg_main>, <&vtg_aux>;
158 };
159
160 sti-tvout@fe000000 {
161 compatible = "st,stih416-tvout";
162 reg = <0xfe000000 0x1000>, <0xfe85a000 0x400>, <0xfe830000 0x10000>;
163 reg-names = "tvout-reg", "hda-reg", "syscfg";
164 reset-names = "tvout";
165 resets = <&softreset STIH416_HDTVOUT_SOFTRESET>;
166 ranges;
167
168 sti-hdmi@fe85c000 {
169 compatible = "st,stih416-hdmi";
170 reg = <0xfe85c000 0x1000>, <0xfe830000 0x10000>;
171 reg-names = "hdmi-reg", "syscfg";
172 interrupts = <GIC_SPI 173 IRQ_TYPE_NONE>;
173 interrupt-names = "irq";
174 clock-names = "pix", "tmds", "phy", "audio";
175 clocks = <&clockgen_c_vcc CLK_S_PIX_HDMI>, <&clockgen_c_vcc CLK_S_TMDS_HDMI>, <&clockgen_c_vcc CLK_S_HDMI_REJECT_PLL>, <&clockgen_b1 CLK_S_PCM_0>;
176 hdmi,hpd-gpio = <&PIO2 5>;
177 };
178
179 sti-hda@fe85a000 {
180 compatible = "st,stih416-hda";
181 reg = <0xfe85a000 0x400>, <0xfe83085c 0x4>;
182 reg-names = "hda-reg", "video-dacs-ctrl";
183 clock-names = "pix", "hddac";
184 clocks = <&clockgen_c_vcc CLK_S_PIX_HD>, <&clockgen_c_vcc CLK_S_HDDAC>;
185 };
186 };
187 };
188 ...
189};
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index f5120046ff80..31894c8c1773 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -201,3 +201,5 @@ source "drivers/gpu/drm/msm/Kconfig"
201source "drivers/gpu/drm/tegra/Kconfig" 201source "drivers/gpu/drm/tegra/Kconfig"
202 202
203source "drivers/gpu/drm/panel/Kconfig" 203source "drivers/gpu/drm/panel/Kconfig"
204
205source "drivers/gpu/drm/sti/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 61d9e9c6bc10..60eb5d425df2 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -64,6 +64,7 @@ obj-$(CONFIG_DRM_QXL) += qxl/
64obj-$(CONFIG_DRM_BOCHS) += bochs/ 64obj-$(CONFIG_DRM_BOCHS) += bochs/
65obj-$(CONFIG_DRM_MSM) += msm/ 65obj-$(CONFIG_DRM_MSM) += msm/
66obj-$(CONFIG_DRM_TEGRA) += tegra/ 66obj-$(CONFIG_DRM_TEGRA) += tegra/
67obj-$(CONFIG_DRM_STI) += sti/
67obj-y += i2c/ 68obj-y += i2c/
68obj-y += panel/ 69obj-y += panel/
69obj-y += bridge/ 70obj-y += bridge/
diff --git a/drivers/gpu/drm/sti/Kconfig b/drivers/gpu/drm/sti/Kconfig
new file mode 100644
index 000000000000..2d9d4252d598
--- /dev/null
+++ b/drivers/gpu/drm/sti/Kconfig
@@ -0,0 +1,14 @@
1config DRM_STI
2 tristate "DRM Support for STMicroelectronics SoC stiH41x Series"
3 depends on DRM && (SOC_STIH415 || SOC_STIH416 || ARCH_MULTIPLATFORM)
4 select DRM_KMS_HELPER
5 select DRM_GEM_CMA_HELPER
6 select DRM_KMS_CMA_HELPER
7 help
8 Choose this option to enable DRM on STM stiH41x chipset
9
10config DRM_STI_FBDEV
11 bool "DRM frame buffer device for STMicroelectronics SoC stiH41x Serie"
12 depends on DRM_STI
13 help
14 Choose this option to enable FBDEV on top of DRM for STM stiH41x chipset
diff --git a/drivers/gpu/drm/sti/Makefile b/drivers/gpu/drm/sti/Makefile
new file mode 100644
index 000000000000..04ac2ceef27f
--- /dev/null
+++ b/drivers/gpu/drm/sti/Makefile
@@ -0,0 +1,21 @@
1sticompositor-y := \
2 sti_layer.o \
3 sti_mixer.o \
4 sti_gdp.o \
5 sti_vid.o \
6 sti_compositor.o \
7 sti_drm_crtc.o \
8 sti_drm_plane.o
9
10stihdmi-y := sti_hdmi.o \
11 sti_hdmi_tx3g0c55phy.o \
12 sti_hdmi_tx3g4c28phy.o \
13
14obj-$(CONFIG_DRM_STI) = \
15 sti_vtg.o \
16 sti_vtac.o \
17 stihdmi.o \
18 sti_hda.o \
19 sti_tvout.o \
20 sticompositor.o \
21 sti_drm_drv.o \ No newline at end of file
diff --git a/drivers/gpu/drm/sti/NOTES b/drivers/gpu/drm/sti/NOTES
new file mode 100644
index 000000000000..57e257969198
--- /dev/null
+++ b/drivers/gpu/drm/sti/NOTES
@@ -0,0 +1,58 @@
11. stiH display hardware IP
2---------------------------
3The STMicroelectronics stiH SoCs use a common chain of HW display IP blocks:
4- The High Quality Video Display Processor (HQVDP) gets video frames from a
5 video decoder and does high quality video processing, including scaling.
6
7- The Compositor is a multiplane, dual-mixer (Main & Aux) digital processor. It
8 has several inputs:
9 - The graphics planes are internally processed by the Generic Display
10 Pipeline (GDP).
11 - The video plug (VID) connects to the HQVDP output.
12 - The cursor handles ... a cursor.
13- The TV OUT pre-formats (convert, clip, round) the compositor output data
14- The HDMI / DVO / HD Analog / SD analog IP builds the video signals
15 - DVO (Digital Video Output) handles a 24bits parallel signal
16 - The HD analog signal is typically driven by a YCbCr cable, supporting up to
17 1080i mode.
18 - The SD analog signal is typically used for legacy TV
19- The VTG (Video Timing Generators) build Vsync signals used by the other HW IP
20Note that some stiH drivers support only a subset of thee HW IP.
21
22 .-------------. .-----------. .-----------.
23GPU >-------------+GDP Main | | +---+ HDMI +--> HDMI
24GPU >-------------+GDP mixer+---+ | :===========:
25GPU >-------------+Cursor | | +---+ DVO +--> 24b//
26 ------- | COMPOSITOR | | TV OUT | :===========:
27 | | | | | +---+ HD analog +--> YCbCr
28Vid >--+ HQVDP +--+VID Aux +---+ | :===========:
29dec | | | mixer| | +---+ SD analog +--> CVBS
30 '-------' '-------------' '-----------' '-----------'
31 .-----------.
32 | main+--> Vsync
33 | VTG |
34 | aux+--> Vsync
35 '-----------'
36
372. DRM / HW mapping
38-------------------
39These IP are mapped to the DRM objects as following:
40- The CRTCs are mapped to the Compositor Main and Aux Mixers
41- The Framebuffers and planes are mapped to the Compositor GDP (non video
42 buffers) and to HQVDP+VID (video buffers)
43- The Cursor is mapped to the Compositor Cursor
44- The Encoders are mapped to the TVOut
45- The Bridges/Connectors are mapped to the HDMI / DVO / HD Analog / SD analog
46
47FB & planes Cursor CRTC Encoders Bridges/Connectors
48 | | | | |
49 | | | | |
50 | .-------------. | .-----------. .-----------. |
51 +------------> |GDP | Main | | | +-> | | HDMI | <-+
52 +------------> |GDP v mixer|<+ | | | :===========: |
53 | |Cursor | | | +-> | | DVO | <-+
54 | ------- | COMPOSITOR | | |TV OUT | | :===========: |
55 | | | | | | | +-> | | HD analog | <-+
56 +-> | HQVDP | |VID Aux |<+ | | | :===========: |
57 | | | mixer| | +-> | | SD analog | <-+
58 '-------' '-------------' '-----------' '-----------'
diff --git a/drivers/gpu/drm/sti/sti_compositor.c b/drivers/gpu/drm/sti/sti_compositor.c
new file mode 100644
index 000000000000..770a725efa20
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_compositor.c
@@ -0,0 +1,279 @@
1/*
2 * Copyright (C) STMicroelectronics SA 2014
3 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
4 * Fabien Dessenne <fabien.dessenne@st.com>
5 * for STMicroelectronics.
6 * License terms: GNU General Public License (GPL), version 2
7 */
8
9#include <linux/component.h>
10#include <linux/module.h>
11#include <linux/platform_device.h>
12#include <linux/reset.h>
13
14#include <drm/drmP.h>
15
16#include "sti_compositor.h"
17#include "sti_drm_crtc.h"
18#include "sti_drm_drv.h"
19#include "sti_drm_plane.h"
20#include "sti_gdp.h"
21#include "sti_vtg.h"
22
23/*
24 * stiH407 compositor properties
25 */
26struct sti_compositor_data stih407_compositor_data = {
27 .nb_subdev = 6,
28 .subdev_desc = {
29 {STI_GPD_SUBDEV, (int)STI_GDP_0, 0x100},
30 {STI_GPD_SUBDEV, (int)STI_GDP_1, 0x200},
31 {STI_GPD_SUBDEV, (int)STI_GDP_2, 0x300},
32 {STI_GPD_SUBDEV, (int)STI_GDP_3, 0x400},
33 {STI_VID_SUBDEV, (int)STI_VID_0, 0x700},
34 {STI_MIXER_MAIN_SUBDEV, STI_MIXER_MAIN, 0xC00}
35 },
36};
37
38/*
39 * stiH416 compositor properties
40 * Note:
41 * on stih416 MIXER_AUX has a different base address from MIXER_MAIN
42 * Moreover, GDPx is different for Main and Aux Mixer. So this subdev map does
43 * not fit for stiH416 if we want to enable the MIXER_AUX.
44 */
45struct sti_compositor_data stih416_compositor_data = {
46 .nb_subdev = 3,
47 .subdev_desc = {
48 {STI_GPD_SUBDEV, (int)STI_GDP_0, 0x100},
49 {STI_GPD_SUBDEV, (int)STI_GDP_1, 0x200},
50 {STI_MIXER_MAIN_SUBDEV, STI_MIXER_MAIN, 0xC00}
51 },
52};
53
54static int sti_compositor_init_subdev(struct sti_compositor *compo,
55 struct sti_compositor_subdev_descriptor *desc,
56 unsigned int array_size)
57{
58 unsigned int i, mixer_id = 0, layer_id = 0;
59
60 for (i = 0; i < array_size; i++) {
61 switch (desc[i].type) {
62 case STI_MIXER_MAIN_SUBDEV:
63 case STI_MIXER_AUX_SUBDEV:
64 compo->mixer[mixer_id++] =
65 sti_mixer_create(compo->dev, desc[i].id,
66 compo->regs + desc[i].offset);
67 break;
68 case STI_GPD_SUBDEV:
69 case STI_VID_SUBDEV:
70 compo->layer[layer_id++] =
71 sti_layer_create(compo->dev, desc[i].id,
72 compo->regs + desc[i].offset);
73 break;
74 /* case STI_CURSOR_SUBDEV : TODO */
75 default:
76 DRM_ERROR("Unknow subdev compoment type\n");
77 return 1;
78 }
79
80 }
81 compo->nb_mixers = mixer_id;
82 compo->nb_layers = layer_id;
83
84 return 0;
85}
86
87static int sti_compositor_bind(struct device *dev, struct device *master,
88 void *data)
89{
90 struct sti_compositor *compo = dev_get_drvdata(dev);
91 struct drm_device *drm_dev = data;
92 unsigned int i, crtc = 0, plane = 0;
93 struct sti_drm_private *dev_priv = drm_dev->dev_private;
94 struct drm_plane *cursor = NULL;
95 struct drm_plane *primary = NULL;
96
97 dev_priv->compo = compo;
98
99 for (i = 0; i < compo->nb_layers; i++) {
100 if (compo->layer[i]) {
101 enum sti_layer_desc desc = compo->layer[i]->desc;
102 enum sti_layer_type type = desc & STI_LAYER_TYPE_MASK;
103 enum drm_plane_type plane_type = DRM_PLANE_TYPE_OVERLAY;
104
105 if (compo->mixer[crtc])
106 plane_type = DRM_PLANE_TYPE_PRIMARY;
107
108 switch (type) {
109 case STI_CUR:
110 cursor = sti_drm_plane_init(drm_dev,
111 compo->layer[i],
112 (1 << crtc) - 1,
113 DRM_PLANE_TYPE_CURSOR);
114 break;
115 case STI_GDP:
116 case STI_VID:
117 primary = sti_drm_plane_init(drm_dev,
118 compo->layer[i],
119 (1 << crtc) - 1, plane_type);
120 plane++;
121 break;
122 }
123
124 /* The first planes are reserved for primary planes*/
125 if (compo->mixer[crtc]) {
126 sti_drm_crtc_init(drm_dev, compo->mixer[crtc],
127 primary, cursor);
128 crtc++;
129 cursor = NULL;
130 }
131 }
132 }
133
134 drm_vblank_init(drm_dev, crtc);
135 /* Allow usage of vblank without having to call drm_irq_install */
136 drm_dev->irq_enabled = 1;
137
138 DRM_DEBUG_DRIVER("Initialized %d DRM CRTC(s) and %d DRM plane(s)\n",
139 crtc, plane);
140 DRM_DEBUG_DRIVER("DRM plane(s) for VID/VDP not created yet\n");
141
142 return 0;
143}
144
145static void sti_compositor_unbind(struct device *dev, struct device *master,
146 void *data)
147{
148 /* do nothing */
149}
150
151static const struct component_ops sti_compositor_ops = {
152 .bind = sti_compositor_bind,
153 .unbind = sti_compositor_unbind,
154};
155
156static const struct of_device_id compositor_of_match[] = {
157 {
158 .compatible = "st,stih416-compositor",
159 .data = &stih416_compositor_data,
160 }, {
161 .compatible = "st,stih407-compositor",
162 .data = &stih407_compositor_data,
163 }, {
164 /* end node */
165 }
166};
167MODULE_DEVICE_TABLE(of, compositor_of_match);
168
169static int sti_compositor_probe(struct platform_device *pdev)
170{
171 struct device *dev = &pdev->dev;
172 struct device_node *np = dev->of_node;
173 struct device_node *vtg_np;
174 struct sti_compositor *compo;
175 struct resource *res;
176 int err;
177
178 compo = devm_kzalloc(dev, sizeof(*compo), GFP_KERNEL);
179 if (!compo) {
180 DRM_ERROR("Failed to allocate compositor context\n");
181 return -ENOMEM;
182 }
183 compo->dev = dev;
184 compo->vtg_vblank_nb.notifier_call = sti_drm_crtc_vblank_cb;
185
186 /* populate data structure depending on compatibility */
187 BUG_ON(!of_match_node(compositor_of_match, np)->data);
188
189 memcpy(&compo->data, of_match_node(compositor_of_match, np)->data,
190 sizeof(struct sti_compositor_data));
191
192 /* Get Memory ressources */
193 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
194 if (res == NULL) {
195 DRM_ERROR("Get memory resource failed\n");
196 return -ENXIO;
197 }
198 compo->regs = devm_ioremap(dev, res->start, resource_size(res));
199 if (compo->regs == NULL) {
200 DRM_ERROR("Register mapping failed\n");
201 return -ENXIO;
202 }
203
204 /* Get clock resources */
205 compo->clk_compo_main = devm_clk_get(dev, "compo_main");
206 if (IS_ERR(compo->clk_compo_main)) {
207 DRM_ERROR("Cannot get compo_main clock\n");
208 return PTR_ERR(compo->clk_compo_main);
209 }
210
211 compo->clk_compo_aux = devm_clk_get(dev, "compo_aux");
212 if (IS_ERR(compo->clk_compo_aux)) {
213 DRM_ERROR("Cannot get compo_aux clock\n");
214 return PTR_ERR(compo->clk_compo_aux);
215 }
216
217 compo->clk_pix_main = devm_clk_get(dev, "pix_main");
218 if (IS_ERR(compo->clk_pix_main)) {
219 DRM_ERROR("Cannot get pix_main clock\n");
220 return PTR_ERR(compo->clk_pix_main);
221 }
222
223 compo->clk_pix_aux = devm_clk_get(dev, "pix_aux");
224 if (IS_ERR(compo->clk_pix_aux)) {
225 DRM_ERROR("Cannot get pix_aux clock\n");
226 return PTR_ERR(compo->clk_pix_aux);
227 }
228
229 /* Get reset resources */
230 compo->rst_main = devm_reset_control_get(dev, "compo-main");
231 /* Take compo main out of reset */
232 if (!IS_ERR(compo->rst_main))
233 reset_control_deassert(compo->rst_main);
234
235 compo->rst_aux = devm_reset_control_get(dev, "compo-aux");
236 /* Take compo aux out of reset */
237 if (!IS_ERR(compo->rst_aux))
238 reset_control_deassert(compo->rst_aux);
239
240 vtg_np = of_parse_phandle(pdev->dev.of_node, "st,vtg", 0);
241 if (vtg_np)
242 compo->vtg_main = of_vtg_find(vtg_np);
243
244 vtg_np = of_parse_phandle(pdev->dev.of_node, "st,vtg", 1);
245 if (vtg_np)
246 compo->vtg_aux = of_vtg_find(vtg_np);
247
248 /* Initialize compositor subdevices */
249 err = sti_compositor_init_subdev(compo, compo->data.subdev_desc,
250 compo->data.nb_subdev);
251 if (err)
252 return err;
253
254 platform_set_drvdata(pdev, compo);
255
256 return component_add(&pdev->dev, &sti_compositor_ops);
257}
258
259static int sti_compositor_remove(struct platform_device *pdev)
260{
261 component_del(&pdev->dev, &sti_compositor_ops);
262 return 0;
263}
264
265static struct platform_driver sti_compositor_driver = {
266 .driver = {
267 .name = "sti-compositor",
268 .owner = THIS_MODULE,
269 .of_match_table = compositor_of_match,
270 },
271 .probe = sti_compositor_probe,
272 .remove = sti_compositor_remove,
273};
274
275module_platform_driver(sti_compositor_driver);
276
277MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
278MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
279MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/sti/sti_compositor.h b/drivers/gpu/drm/sti/sti_compositor.h
new file mode 100644
index 000000000000..3ea19db72e0f
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_compositor.h
@@ -0,0 +1,90 @@
1/*
2 * Copyright (C) STMicroelectronics SA 2014
3 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
4 * Fabien Dessenne <fabien.dessenne@st.com>
5 * for STMicroelectronics.
6 * License terms: GNU General Public License (GPL), version 2
7 */
8
9#ifndef _STI_COMPOSITOR_H_
10#define _STI_COMPOSITOR_H_
11
12#include <linux/clk.h>
13#include <linux/kernel.h>
14
15#include "sti_layer.h"
16#include "sti_mixer.h"
17
18#define WAIT_NEXT_VSYNC_MS 50 /*ms*/
19
20#define STI_MAX_LAYER 8
21#define STI_MAX_MIXER 2
22
23enum sti_compositor_subdev_type {
24 STI_MIXER_MAIN_SUBDEV,
25 STI_MIXER_AUX_SUBDEV,
26 STI_GPD_SUBDEV,
27 STI_VID_SUBDEV,
28 STI_CURSOR_SUBDEV,
29};
30
31struct sti_compositor_subdev_descriptor {
32 enum sti_compositor_subdev_type type;
33 int id;
34 unsigned int offset;
35};
36
37/**
38 * STI Compositor data structure
39 *
40 * @nb_subdev: number of subdevices supported by the compositor
41 * @subdev_desc: subdev list description
42 */
43#define MAX_SUBDEV 9
44struct sti_compositor_data {
45 unsigned int nb_subdev;
46 struct sti_compositor_subdev_descriptor subdev_desc[MAX_SUBDEV];
47};
48
49/**
50 * STI Compositor structure
51 *
52 * @dev: driver device
53 * @regs: registers (main)
54 * @data: device data
55 * @clk_compo_main: clock for main compo
56 * @clk_compo_aux: clock for aux compo
57 * @clk_pix_main: pixel clock for main path
58 * @clk_pix_aux: pixel clock for aux path
59 * @rst_main: reset control of the main path
60 * @rst_aux: reset control of the aux path
61 * @mixer: array of mixers
62 * @vtg_main: vtg for main data path
63 * @vtg_aux: vtg for auxillary data path
64 * @layer: array of layers
65 * @nb_mixers: number of mixers for this compositor
66 * @nb_layers: number of layers (GDP,VID,...) for this compositor
67 * @enable: true if compositor is enable else false
68 * @vtg_vblank_nb: callback for VTG VSYNC notification
69 */
70struct sti_compositor {
71 struct device *dev;
72 void __iomem *regs;
73 struct sti_compositor_data data;
74 struct clk *clk_compo_main;
75 struct clk *clk_compo_aux;
76 struct clk *clk_pix_main;
77 struct clk *clk_pix_aux;
78 struct reset_control *rst_main;
79 struct reset_control *rst_aux;
80 struct sti_mixer *mixer[STI_MAX_MIXER];
81 struct sti_vtg *vtg_main;
82 struct sti_vtg *vtg_aux;
83 struct sti_layer *layer[STI_MAX_LAYER];
84 int nb_mixers;
85 int nb_layers;
86 bool enable;
87 struct notifier_block vtg_vblank_nb;
88};
89
90#endif
diff --git a/drivers/gpu/drm/sti/sti_drm_crtc.c b/drivers/gpu/drm/sti/sti_drm_crtc.c
new file mode 100644
index 000000000000..6eba648cf7b3
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_drm_crtc.c
@@ -0,0 +1,423 @@
1/*
2 * Copyright (C) STMicroelectronics SA 2014
3 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
4 * Fabien Dessenne <fabien.dessenne@st.com>
5 * for STMicroelectronics.
6 * License terms: GNU General Public License (GPL), version 2
7 */
8
9#include <linux/clk.h>
10
11#include <drm/drmP.h>
12#include <drm/drm_crtc_helper.h>
13
14#include "sti_compositor.h"
15#include "sti_drm_drv.h"
16#include "sti_drm_crtc.h"
17#include "sti_vtg.h"
18
19static void sti_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
20{
21 DRM_DEBUG_KMS("\n");
22}
23
24static void sti_drm_crtc_prepare(struct drm_crtc *crtc)
25{
26 struct sti_mixer *mixer = to_sti_mixer(crtc);
27 struct device *dev = mixer->dev;
28 struct sti_compositor *compo = dev_get_drvdata(dev);
29
30 compo->enable = true;
31
32 /* Prepare and enable the compo IP clock */
33 if (mixer->id == STI_MIXER_MAIN) {
34 if (clk_prepare_enable(compo->clk_compo_main))
35 DRM_INFO("Failed to prepare/enable compo_main clk\n");
36 } else {
37 if (clk_prepare_enable(compo->clk_compo_aux))
38 DRM_INFO("Failed to prepare/enable compo_aux clk\n");
39 }
40}
41
42static void sti_drm_crtc_commit(struct drm_crtc *crtc)
43{
44 struct sti_mixer *mixer = to_sti_mixer(crtc);
45 struct device *dev = mixer->dev;
46 struct sti_compositor *compo = dev_get_drvdata(dev);
47 struct sti_layer *layer;
48
49 if ((!mixer || !compo)) {
50 DRM_ERROR("Can not find mixer or compositor)\n");
51 return;
52 }
53
54 /* get GDP which is reserved to the CRTC FB */
55 layer = to_sti_layer(crtc->primary);
56 if (layer)
57 sti_layer_commit(layer);
58 else
59 DRM_ERROR("Can not find CRTC dedicated plane (GDP0)\n");
60
61 /* Enable layer on mixer */
62 if (sti_mixer_set_layer_status(mixer, layer, true))
63 DRM_ERROR("Can not enable layer at mixer\n");
64}
65
66static bool sti_drm_crtc_mode_fixup(struct drm_crtc *crtc,
67 const struct drm_display_mode *mode,
68 struct drm_display_mode *adjusted_mode)
69{
70 /* accept the provided drm_display_mode, do not fix it up */
71 return true;
72}
73
74static int
75sti_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
76 struct drm_display_mode *adjusted_mode, int x, int y,
77 struct drm_framebuffer *old_fb)
78{
79 struct sti_mixer *mixer = to_sti_mixer(crtc);
80 struct device *dev = mixer->dev;
81 struct sti_compositor *compo = dev_get_drvdata(dev);
82 struct sti_layer *layer;
83 struct clk *clk;
84 int rate = mode->clock * 1000;
85 int res;
86 unsigned int w, h;
87
88 DRM_DEBUG_KMS("CRTC:%d (%s) fb:%d mode:%d (%s)\n",
89 crtc->base.id, sti_mixer_to_str(mixer),
90 crtc->primary->fb->base.id, mode->base.id, mode->name);
91
92 DRM_DEBUG_KMS("%d %d %d %d %d %d %d %d %d %d 0x%x 0x%x\n",
93 mode->vrefresh, mode->clock,
94 mode->hdisplay,
95 mode->hsync_start, mode->hsync_end,
96 mode->htotal,
97 mode->vdisplay,
98 mode->vsync_start, mode->vsync_end,
99 mode->vtotal, mode->type, mode->flags);
100
101 /* Set rate and prepare/enable pixel clock */
102 if (mixer->id == STI_MIXER_MAIN)
103 clk = compo->clk_pix_main;
104 else
105 clk = compo->clk_pix_aux;
106
107 res = clk_set_rate(clk, rate);
108 if (res < 0) {
109 DRM_ERROR("Cannot set rate (%dHz) for pix clk\n", rate);
110 return -EINVAL;
111 }
112 if (clk_prepare_enable(clk)) {
113 DRM_ERROR("Failed to prepare/enable pix clk\n");
114 return -EINVAL;
115 }
116
117 sti_vtg_set_config(mixer->id == STI_MIXER_MAIN ?
118 compo->vtg_main : compo->vtg_aux, &crtc->mode);
119
120 /* a GDP is reserved to the CRTC FB */
121 layer = to_sti_layer(crtc->primary);
122 if (!layer) {
123 DRM_ERROR("Can not find GDP0)\n");
124 return -EINVAL;
125 }
126
127 /* copy the mode data adjusted by mode_fixup() into crtc->mode
128 * so that hardware can be set to proper mode
129 */
130 memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode));
131
132 res = sti_mixer_set_layer_depth(mixer, layer);
133 if (res) {
134 DRM_ERROR("Can not set layer depth\n");
135 return -EINVAL;
136 }
137 res = sti_mixer_active_video_area(mixer, &crtc->mode);
138 if (res) {
139 DRM_ERROR("Can not set active video area\n");
140 return -EINVAL;
141 }
142
143 w = crtc->primary->fb->width - x;
144 h = crtc->primary->fb->height - y;
145
146 return sti_layer_prepare(layer, crtc->primary->fb, &crtc->mode,
147 mixer->id, 0, 0, w, h, x, y, w, h);
148}
149
150static int sti_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
151 struct drm_framebuffer *old_fb)
152{
153 struct sti_mixer *mixer = to_sti_mixer(crtc);
154 struct device *dev = mixer->dev;
155 struct sti_compositor *compo = dev_get_drvdata(dev);
156 struct sti_layer *layer;
157 unsigned int w, h;
158 int ret;
159
160 DRM_DEBUG_KMS("CRTC:%d (%s) fb:%d (%d,%d)\n",
161 crtc->base.id, sti_mixer_to_str(mixer),
162 crtc->primary->fb->base.id, x, y);
163
164 /* GDP is reserved to the CRTC FB */
165 layer = to_sti_layer(crtc->primary);
166 if (!layer) {
167 DRM_ERROR("Can not find GDP0)\n");
168 ret = -EINVAL;
169 goto out;
170 }
171
172 w = crtc->primary->fb->width - crtc->x;
173 h = crtc->primary->fb->height - crtc->y;
174
175 ret = sti_layer_prepare(layer, crtc->primary->fb, &crtc->mode,
176 mixer->id, 0, 0, w, h,
177 crtc->x, crtc->y, w, h);
178 if (ret) {
179 DRM_ERROR("Can not prepare layer\n");
180 goto out;
181 }
182
183 sti_drm_crtc_commit(crtc);
184out:
185 return ret;
186}
187
188static void sti_drm_crtc_load_lut(struct drm_crtc *crtc)
189{
190 /* do nothing */
191}
192
193static void sti_drm_crtc_disable(struct drm_crtc *crtc)
194{
195 struct sti_mixer *mixer = to_sti_mixer(crtc);
196 struct device *dev = mixer->dev;
197 struct sti_compositor *compo = dev_get_drvdata(dev);
198 struct sti_layer *layer;
199
200 if (!compo->enable)
201 return;
202
203 DRM_DEBUG_KMS("CRTC:%d (%s)\n", crtc->base.id, sti_mixer_to_str(mixer));
204
205 /* Disable Background */
206 sti_mixer_set_background_status(mixer, false);
207
208 /* Disable GDP */
209 layer = to_sti_layer(crtc->primary);
210 if (!layer) {
211 DRM_ERROR("Cannot find GDP0\n");
212 return;
213 }
214
215 /* Disable layer at mixer level */
216 if (sti_mixer_set_layer_status(mixer, layer, false))
217 DRM_ERROR("Can not disable %s layer at mixer\n",
218 sti_layer_to_str(layer));
219
220 /* Wait a while to be sure that a Vsync event is received */
221 msleep(WAIT_NEXT_VSYNC_MS);
222
223 /* Then disable layer itself */
224 sti_layer_disable(layer);
225
226 drm_vblank_off(crtc->dev, mixer->id);
227
228 /* Disable pixel clock and compo IP clocks */
229 if (mixer->id == STI_MIXER_MAIN) {
230 clk_disable_unprepare(compo->clk_pix_main);
231 clk_disable_unprepare(compo->clk_compo_main);
232 } else {
233 clk_disable_unprepare(compo->clk_pix_aux);
234 clk_disable_unprepare(compo->clk_compo_aux);
235 }
236
237 compo->enable = false;
238}
239
240static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = {
241 .dpms = sti_drm_crtc_dpms,
242 .prepare = sti_drm_crtc_prepare,
243 .commit = sti_drm_crtc_commit,
244 .mode_fixup = sti_drm_crtc_mode_fixup,
245 .mode_set = sti_drm_crtc_mode_set,
246 .mode_set_base = sti_drm_crtc_mode_set_base,
247 .load_lut = sti_drm_crtc_load_lut,
248 .disable = sti_drm_crtc_disable,
249};
250
251static int sti_drm_crtc_page_flip(struct drm_crtc *crtc,
252 struct drm_framebuffer *fb,
253 struct drm_pending_vblank_event *event,
254 uint32_t page_flip_flags)
255{
256 struct drm_device *drm_dev = crtc->dev;
257 struct drm_framebuffer *old_fb;
258 struct sti_mixer *mixer = to_sti_mixer(crtc);
259 unsigned long flags;
260 int ret;
261
262 DRM_DEBUG_KMS("fb %d --> fb %d\n",
263 crtc->primary->fb->base.id, fb->base.id);
264
265 mutex_lock(&drm_dev->struct_mutex);
266
267 old_fb = crtc->primary->fb;
268 crtc->primary->fb = fb;
269 ret = sti_drm_crtc_mode_set_base(crtc, crtc->x, crtc->y, old_fb);
270 if (ret) {
271 DRM_ERROR("failed\n");
272 crtc->primary->fb = old_fb;
273 goto out;
274 }
275
276 if (event) {
277 event->pipe = mixer->id;
278
279 ret = drm_vblank_get(drm_dev, event->pipe);
280 if (ret) {
281 DRM_ERROR("Cannot get vblank\n");
282 goto out;
283 }
284
285 spin_lock_irqsave(&drm_dev->event_lock, flags);
286 if (mixer->pending_event) {
287 drm_vblank_put(drm_dev, event->pipe);
288 ret = -EBUSY;
289 } else {
290 mixer->pending_event = event;
291 }
292 spin_unlock_irqrestore(&drm_dev->event_lock, flags);
293 }
294out:
295 mutex_unlock(&drm_dev->struct_mutex);
296 return ret;
297}
298
299static void sti_drm_crtc_destroy(struct drm_crtc *crtc)
300{
301 DRM_DEBUG_KMS("\n");
302 drm_crtc_cleanup(crtc);
303}
304
305static int sti_drm_crtc_set_property(struct drm_crtc *crtc,
306 struct drm_property *property,
307 uint64_t val)
308{
309 DRM_DEBUG_KMS("\n");
310 return 0;
311}
312
313int sti_drm_crtc_vblank_cb(struct notifier_block *nb,
314 unsigned long event, void *data)
315{
316 struct drm_device *drm_dev;
317 struct sti_compositor *compo =
318 container_of(nb, struct sti_compositor, vtg_vblank_nb);
319 int *crtc = data;
320 unsigned long flags;
321 struct sti_drm_private *priv;
322
323 drm_dev = compo->mixer[*crtc]->drm_crtc.dev;
324 priv = drm_dev->dev_private;
325
326 if ((event != VTG_TOP_FIELD_EVENT) &&
327 (event != VTG_BOTTOM_FIELD_EVENT)) {
328 DRM_ERROR("unknown event: %lu\n", event);
329 return -EINVAL;
330 }
331
332 drm_handle_vblank(drm_dev, *crtc);
333
334 spin_lock_irqsave(&drm_dev->event_lock, flags);
335 if (compo->mixer[*crtc]->pending_event) {
336 drm_send_vblank_event(drm_dev, -1,
337 compo->mixer[*crtc]->pending_event);
338 drm_vblank_put(drm_dev, *crtc);
339 compo->mixer[*crtc]->pending_event = NULL;
340 }
341 spin_unlock_irqrestore(&drm_dev->event_lock, flags);
342
343 return 0;
344}
345
346int sti_drm_crtc_enable_vblank(struct drm_device *dev, int crtc)
347{
348 struct sti_drm_private *dev_priv = dev->dev_private;
349 struct sti_compositor *compo = dev_priv->compo;
350 struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb;
351
352 if (sti_vtg_register_client(crtc == STI_MIXER_MAIN ?
353 compo->vtg_main : compo->vtg_aux,
354 vtg_vblank_nb, crtc)) {
355 DRM_ERROR("Cannot register VTG notifier\n");
356 return -EINVAL;
357 }
358
359 return 0;
360}
361EXPORT_SYMBOL(sti_drm_crtc_enable_vblank);
362
363void sti_drm_crtc_disable_vblank(struct drm_device *dev, int crtc)
364{
365 struct sti_drm_private *priv = dev->dev_private;
366 struct sti_compositor *compo = priv->compo;
367 struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb;
368 unsigned long flags;
369
370 DRM_DEBUG_DRIVER("\n");
371
372 if (sti_vtg_unregister_client(crtc == STI_MIXER_MAIN ?
373 compo->vtg_main : compo->vtg_aux, vtg_vblank_nb))
374 DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n");
375
376 /* free the resources of the pending requests */
377 spin_lock_irqsave(&dev->event_lock, flags);
378 if (compo->mixer[crtc]->pending_event) {
379 drm_vblank_put(dev, crtc);
380 compo->mixer[crtc]->pending_event = NULL;
381 }
382 spin_unlock_irqrestore(&dev->event_lock, flags);
383
384}
385EXPORT_SYMBOL(sti_drm_crtc_disable_vblank);
386
387static struct drm_crtc_funcs sti_crtc_funcs = {
388 .set_config = drm_crtc_helper_set_config,
389 .page_flip = sti_drm_crtc_page_flip,
390 .destroy = sti_drm_crtc_destroy,
391 .set_property = sti_drm_crtc_set_property,
392};
393
394bool sti_drm_crtc_is_main(struct drm_crtc *crtc)
395{
396 struct sti_mixer *mixer = to_sti_mixer(crtc);
397
398 if (mixer->id == STI_MIXER_MAIN)
399 return true;
400
401 return false;
402}
403
404int sti_drm_crtc_init(struct drm_device *drm_dev, struct sti_mixer *mixer,
405 struct drm_plane *primary, struct drm_plane *cursor)
406{
407 struct drm_crtc *crtc = &mixer->drm_crtc;
408 int res;
409
410 res = drm_crtc_init_with_planes(drm_dev, crtc, primary, cursor,
411 &sti_crtc_funcs);
412 if (res) {
413 DRM_ERROR("Can not initialze CRTC\n");
414 return -EINVAL;
415 }
416
417 drm_crtc_helper_add(crtc, &sti_crtc_helper_funcs);
418
419 DRM_DEBUG_DRIVER("drm CRTC:%d mapped to %s\n",
420 crtc->base.id, sti_mixer_to_str(mixer));
421
422 return 0;
423}
diff --git a/drivers/gpu/drm/sti/sti_drm_crtc.h b/drivers/gpu/drm/sti/sti_drm_crtc.h
new file mode 100644
index 000000000000..caca8b14f017
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_drm_crtc.h
@@ -0,0 +1,22 @@
1/*
2 * Copyright (C) STMicroelectronics SA 2014
3 * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
5 */
6
7#ifndef _STI_DRM_CRTC_H_
8#define _STI_DRM_CRTC_H_
9
10#include <drm/drmP.h>
11
12struct sti_mixer;
13
14int sti_drm_crtc_init(struct drm_device *drm_dev, struct sti_mixer *mixer,
15 struct drm_plane *primary, struct drm_plane *cursor);
16int sti_drm_crtc_enable_vblank(struct drm_device *dev, int crtc);
17void sti_drm_crtc_disable_vblank(struct drm_device *dev, int crtc);
18int sti_drm_crtc_vblank_cb(struct notifier_block *nb,
19 unsigned long event, void *data);
20bool sti_drm_crtc_is_main(struct drm_crtc *drm_crtc);
21
22#endif
diff --git a/drivers/gpu/drm/sti/sti_drm_drv.c b/drivers/gpu/drm/sti/sti_drm_drv.c
new file mode 100644
index 000000000000..a7cc24917a96
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_drm_drv.c
@@ -0,0 +1,241 @@
1/*
2 * Copyright (C) STMicroelectronics SA 2014
3 * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
5 */
6
7#include <drm/drmP.h>
8
9#include <linux/component.h>
10#include <linux/debugfs.h>
11#include <linux/kernel.h>
12#include <linux/module.h>
13#include <linux/of_platform.h>
14
15#include <drm/drm_crtc_helper.h>
16#include <drm/drm_gem_cma_helper.h>
17#include <drm/drm_fb_cma_helper.h>
18
19#include "sti_drm_drv.h"
20#include "sti_drm_crtc.h"
21
22#define DRIVER_NAME "sti"
23#define DRIVER_DESC "STMicroelectronics SoC DRM"
24#define DRIVER_DATE "20140601"
25#define DRIVER_MAJOR 1
26#define DRIVER_MINOR 0
27
28#define STI_MAX_FB_HEIGHT 4096
29#define STI_MAX_FB_WIDTH 4096
30
31static struct drm_mode_config_funcs sti_drm_mode_config_funcs = {
32 .fb_create = drm_fb_cma_create,
33};
34
35static void sti_drm_mode_config_init(struct drm_device *dev)
36{
37 dev->mode_config.min_width = 0;
38 dev->mode_config.min_height = 0;
39
40 /*
41 * set max width and height as default value.
42 * this value would be used to check framebuffer size limitation
43 * at drm_mode_addfb().
44 */
45 dev->mode_config.max_width = STI_MAX_FB_HEIGHT;
46 dev->mode_config.max_height = STI_MAX_FB_WIDTH;
47
48 dev->mode_config.funcs = &sti_drm_mode_config_funcs;
49}
50
51static int sti_drm_load(struct drm_device *dev, unsigned long flags)
52{
53 struct sti_drm_private *private;
54 int ret;
55
56 private = kzalloc(sizeof(struct sti_drm_private), GFP_KERNEL);
57 if (!private) {
58 DRM_ERROR("Failed to allocate private\n");
59 return -ENOMEM;
60 }
61 dev->dev_private = (void *)private;
62 private->drm_dev = dev;
63
64 drm_mode_config_init(dev);
65 drm_kms_helper_poll_init(dev);
66
67 sti_drm_mode_config_init(dev);
68
69 ret = component_bind_all(dev->dev, dev);
70 if (ret)
71 return ret;
72
73 drm_helper_disable_unused_functions(dev);
74
75#ifdef CONFIG_DRM_STI_FBDEV
76 drm_fbdev_cma_init(dev, 32,
77 dev->mode_config.num_crtc,
78 dev->mode_config.num_connector);
79#endif
80 return 0;
81}
82
83static const struct file_operations sti_drm_driver_fops = {
84 .owner = THIS_MODULE,
85 .open = drm_open,
86 .mmap = drm_gem_cma_mmap,
87 .poll = drm_poll,
88 .read = drm_read,
89 .unlocked_ioctl = drm_ioctl,
90#ifdef CONFIG_COMPAT
91 .compat_ioctl = drm_compat_ioctl,
92#endif
93 .release = drm_release,
94};
95
96static struct dma_buf *sti_drm_gem_prime_export(struct drm_device *dev,
97 struct drm_gem_object *obj,
98 int flags)
99{
100 /* we want to be able to write in mmapped buffer */
101 flags |= O_RDWR;
102 return drm_gem_prime_export(dev, obj, flags);
103}
104
105static struct drm_driver sti_drm_driver = {
106 .driver_features = DRIVER_HAVE_IRQ | DRIVER_MODESET |
107 DRIVER_GEM | DRIVER_PRIME,
108 .load = sti_drm_load,
109 .gem_free_object = drm_gem_cma_free_object,
110 .gem_vm_ops = &drm_gem_cma_vm_ops,
111 .dumb_create = drm_gem_cma_dumb_create,
112 .dumb_map_offset = drm_gem_cma_dumb_map_offset,
113 .dumb_destroy = drm_gem_dumb_destroy,
114 .fops = &sti_drm_driver_fops,
115
116 .get_vblank_counter = drm_vblank_count,
117 .enable_vblank = sti_drm_crtc_enable_vblank,
118 .disable_vblank = sti_drm_crtc_disable_vblank,
119
120 .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
121 .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
122 .gem_prime_export = sti_drm_gem_prime_export,
123 .gem_prime_import = drm_gem_prime_import,
124 .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
125 .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
126 .gem_prime_vmap = drm_gem_cma_prime_vmap,
127 .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
128 .gem_prime_mmap = drm_gem_cma_prime_mmap,
129
130 .name = DRIVER_NAME,
131 .desc = DRIVER_DESC,
132 .date = DRIVER_DATE,
133 .major = DRIVER_MAJOR,
134 .minor = DRIVER_MINOR,
135};
136
137static int compare_of(struct device *dev, void *data)
138{
139 return dev->of_node == data;
140}
141
142static int sti_drm_bind(struct device *dev)
143{
144 return drm_platform_init(&sti_drm_driver, to_platform_device(dev));
145}
146
147static void sti_drm_unbind(struct device *dev)
148{
149 drm_put_dev(dev_get_drvdata(dev));
150}
151
152static const struct component_master_ops sti_drm_ops = {
153 .bind = sti_drm_bind,
154 .unbind = sti_drm_unbind,
155};
156
157static int sti_drm_master_probe(struct platform_device *pdev)
158{
159 struct device *dev = &pdev->dev;
160 struct device_node *node = dev->parent->of_node;
161 struct device_node *child_np;
162 struct component_match *match = NULL;
163
164 dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
165
166 child_np = of_get_next_available_child(node, NULL);
167
168 while (child_np) {
169 component_match_add(dev, &match, compare_of, child_np);
170 of_node_put(child_np);
171 child_np = of_get_next_available_child(node, child_np);
172 }
173
174 return component_master_add_with_match(dev, &sti_drm_ops, match);
175}
176
177static int sti_drm_master_remove(struct platform_device *pdev)
178{
179 component_master_del(&pdev->dev, &sti_drm_ops);
180 return 0;
181}
182
183static struct platform_driver sti_drm_master_driver = {
184 .probe = sti_drm_master_probe,
185 .remove = sti_drm_master_remove,
186 .driver = {
187 .owner = THIS_MODULE,
188 .name = DRIVER_NAME "__master",
189 },
190};
191
192static int sti_drm_platform_probe(struct platform_device *pdev)
193{
194 struct device *dev = &pdev->dev;
195 struct device_node *node = dev->of_node;
196 struct platform_device *master;
197
198 of_platform_populate(node, NULL, NULL, dev);
199
200 platform_driver_register(&sti_drm_master_driver);
201 master = platform_device_register_resndata(dev,
202 DRIVER_NAME "__master", -1,
203 NULL, 0, NULL, 0);
204 if (!master)
205 return -EINVAL;
206
207 platform_set_drvdata(pdev, master);
208 return 0;
209}
210
211static int sti_drm_platform_remove(struct platform_device *pdev)
212{
213 struct platform_device *master = platform_get_drvdata(pdev);
214
215 of_platform_depopulate(&pdev->dev);
216 platform_device_unregister(master);
217 platform_driver_unregister(&sti_drm_master_driver);
218 return 0;
219}
220
221static const struct of_device_id sti_drm_dt_ids[] = {
222 { .compatible = "st,sti-display-subsystem", },
223 { /* end node */ },
224};
225MODULE_DEVICE_TABLE(of, sti_drm_dt_ids);
226
227static struct platform_driver sti_drm_platform_driver = {
228 .probe = sti_drm_platform_probe,
229 .remove = sti_drm_platform_remove,
230 .driver = {
231 .owner = THIS_MODULE,
232 .name = DRIVER_NAME,
233 .of_match_table = sti_drm_dt_ids,
234 },
235};
236
237module_platform_driver(sti_drm_platform_driver);
238
239MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
240MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
241MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/sti/sti_drm_drv.h b/drivers/gpu/drm/sti/sti_drm_drv.h
new file mode 100644
index 000000000000..ec5e2eb8dff9
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_drm_drv.h
@@ -0,0 +1,29 @@
1/*
2 * Copyright (C) STMicroelectronics SA 2014
3 * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
5 */
6
7#ifndef _STI_DRM_DRV_H_
8#define _STI_DRM_DRV_H_
9
10#include <drm/drmP.h>
11
12struct sti_compositor;
13struct sti_tvout;
14
15/**
16 * STI drm private structure
17 * This structure is stored as private in the drm_device
18 *
19 * @compo: compositor
20 * @plane_zorder_property: z-order property for CRTC planes
21 * @drm_dev: drm device
22 */
23struct sti_drm_private {
24 struct sti_compositor *compo;
25 struct drm_property *plane_zorder_property;
26 struct drm_device *drm_dev;
27};
28
29#endif
diff --git a/drivers/gpu/drm/sti/sti_drm_plane.c b/drivers/gpu/drm/sti/sti_drm_plane.c
new file mode 100644
index 000000000000..f4118d4cac22
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_drm_plane.c
@@ -0,0 +1,195 @@
1/*
2 * Copyright (C) STMicroelectronics SA 2014
3 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
4 * Fabien Dessenne <fabien.dessenne@st.com>
5 * for STMicroelectronics.
6 * License terms: GNU General Public License (GPL), version 2
7 */
8
9#include "sti_compositor.h"
10#include "sti_drm_drv.h"
11#include "sti_drm_plane.h"
12#include "sti_vtg.h"
13
14enum sti_layer_desc sti_layer_default_zorder[] = {
15 STI_GDP_0,
16 STI_VID_0,
17 STI_GDP_1,
18 STI_VID_1,
19 STI_GDP_2,
20 STI_GDP_3,
21};
22
23/* (Background) < GDP0 < VID0 < GDP1 < VID1 < GDP2 < GDP3 < (ForeGround) */
24
25static int
26sti_drm_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
27 struct drm_framebuffer *fb, int crtc_x, int crtc_y,
28 unsigned int crtc_w, unsigned int crtc_h,
29 uint32_t src_x, uint32_t src_y,
30 uint32_t src_w, uint32_t src_h)
31{
32 struct sti_layer *layer = to_sti_layer(plane);
33 struct sti_mixer *mixer = to_sti_mixer(crtc);
34 int res;
35
36 DRM_DEBUG_KMS("CRTC:%d (%s) drm plane:%d (%s) drm fb:%d\n",
37 crtc->base.id, sti_mixer_to_str(mixer),
38 plane->base.id, sti_layer_to_str(layer), fb->base.id);
39 DRM_DEBUG_KMS("(%dx%d)@(%d,%d)\n", crtc_w, crtc_h, crtc_x, crtc_y);
40
41 res = sti_mixer_set_layer_depth(mixer, layer);
42 if (res) {
43 DRM_ERROR("Can not set layer depth\n");
44 return res;
45 }
46
47 /* src_x are in 16.16 format. */
48 res = sti_layer_prepare(layer, fb, &crtc->mode, mixer->id,
49 crtc_x, crtc_y, crtc_w, crtc_h,
50 src_x >> 16, src_y >> 16,
51 src_w >> 16, src_h >> 16);
52 if (res) {
53 DRM_ERROR("Layer prepare failed\n");
54 return res;
55 }
56
57 res = sti_layer_commit(layer);
58 if (res) {
59 DRM_ERROR("Layer commit failed\n");
60 return res;
61 }
62
63 res = sti_mixer_set_layer_status(mixer, layer, true);
64 if (res) {
65 DRM_ERROR("Can not enable layer at mixer\n");
66 return res;
67 }
68
69 return 0;
70}
71
72static int sti_drm_disable_plane(struct drm_plane *plane)
73{
74 struct sti_layer *layer;
75 struct sti_mixer *mixer;
76 int lay_res, mix_res;
77
78 if (!plane->crtc) {
79 DRM_DEBUG_DRIVER("drm plane:%d not enabled\n", plane->base.id);
80 return 0;
81 }
82 layer = to_sti_layer(plane);
83 mixer = to_sti_mixer(plane->crtc);
84
85 DRM_DEBUG_DRIVER("CRTC:%d (%s) drm plane:%d (%s)\n",
86 plane->crtc->base.id, sti_mixer_to_str(mixer),
87 plane->base.id, sti_layer_to_str(layer));
88
89 /* Disable layer at mixer level */
90 mix_res = sti_mixer_set_layer_status(mixer, layer, false);
91 if (mix_res)
92 DRM_ERROR("Can not disable layer at mixer\n");
93
94 /* Wait a while to be sure that a Vsync event is received */
95 msleep(WAIT_NEXT_VSYNC_MS);
96
97 /* Then disable layer itself */
98 lay_res = sti_layer_disable(layer);
99 if (lay_res)
100 DRM_ERROR("Layer disable failed\n");
101
102 if (lay_res || mix_res)
103 return -EINVAL;
104
105 return 0;
106}
107
108static void sti_drm_plane_destroy(struct drm_plane *plane)
109{
110 DRM_DEBUG_DRIVER("\n");
111
112 sti_drm_disable_plane(plane);
113 drm_plane_cleanup(plane);
114}
115
116static int sti_drm_plane_set_property(struct drm_plane *plane,
117 struct drm_property *property,
118 uint64_t val)
119{
120 struct drm_device *dev = plane->dev;
121 struct sti_drm_private *private = dev->dev_private;
122 struct sti_layer *layer = to_sti_layer(plane);
123
124 DRM_DEBUG_DRIVER("\n");
125
126 if (property == private->plane_zorder_property) {
127 layer->zorder = val;
128 return 0;
129 }
130
131 return -EINVAL;
132}
133
134static struct drm_plane_funcs sti_drm_plane_funcs = {
135 .update_plane = sti_drm_update_plane,
136 .disable_plane = sti_drm_disable_plane,
137 .destroy = sti_drm_plane_destroy,
138 .set_property = sti_drm_plane_set_property,
139};
140
141static void sti_drm_plane_attach_zorder_property(struct drm_plane *plane,
142 uint64_t default_val)
143{
144 struct drm_device *dev = plane->dev;
145 struct sti_drm_private *private = dev->dev_private;
146 struct drm_property *prop;
147 struct sti_layer *layer = to_sti_layer(plane);
148
149 prop = private->plane_zorder_property;
150 if (!prop) {
151 prop = drm_property_create_range(dev, 0, "zpos", 0,
152 GAM_MIXER_NB_DEPTH_LEVEL - 1);
153 if (!prop)
154 return;
155
156 private->plane_zorder_property = prop;
157 }
158
159 drm_object_attach_property(&plane->base, prop, default_val);
160 layer->zorder = default_val;
161}
162
163struct drm_plane *sti_drm_plane_init(struct drm_device *dev,
164 struct sti_layer *layer,
165 unsigned int possible_crtcs,
166 enum drm_plane_type type)
167{
168 int err, i;
169 uint64_t default_zorder = 0;
170
171 err = drm_universal_plane_init(dev, &layer->plane, possible_crtcs,
172 &sti_drm_plane_funcs,
173 sti_layer_get_formats(layer),
174 sti_layer_get_nb_formats(layer), type);
175 if (err) {
176 DRM_ERROR("Failed to initialize plane\n");
177 return NULL;
178 }
179
180 for (i = 0; i < ARRAY_SIZE(sti_layer_default_zorder); i++)
181 if (sti_layer_default_zorder[i] == layer->desc)
182 break;
183
184 default_zorder = i;
185
186 if (type == DRM_PLANE_TYPE_OVERLAY)
187 sti_drm_plane_attach_zorder_property(&layer->plane,
188 default_zorder);
189
190 DRM_DEBUG_DRIVER("drm plane:%d mapped to %s with zorder:%llu\n",
191 layer->plane.base.id,
192 sti_layer_to_str(layer), default_zorder);
193
194 return &layer->plane;
195}
diff --git a/drivers/gpu/drm/sti/sti_drm_plane.h b/drivers/gpu/drm/sti/sti_drm_plane.h
new file mode 100644
index 000000000000..4f191839f2a7
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_drm_plane.h
@@ -0,0 +1,18 @@
1/*
2 * Copyright (C) STMicroelectronics SA 2014
3 * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
5 */
6
7#ifndef _STI_DRM_PLANE_H_
8#define _STI_DRM_PLANE_H_
9
10#include <drm/drmP.h>
11
12struct sti_layer;
13
14struct drm_plane *sti_drm_plane_init(struct drm_device *dev,
15 struct sti_layer *layer,
16 unsigned int possible_crtcs,
17 enum drm_plane_type type);
18#endif
diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c
new file mode 100644
index 000000000000..4e30b74559f5
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_gdp.c
@@ -0,0 +1,549 @@
1/*
2 * Copyright (C) STMicroelectronics SA 2014
3 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
4 * Fabien Dessenne <fabien.dessenne@st.com>
5 * for STMicroelectronics.
6 * License terms: GNU General Public License (GPL), version 2
7 */
8
9#include <linux/clk.h>
10#include <linux/dma-mapping.h>
11
12#include "sti_compositor.h"
13#include "sti_gdp.h"
14#include "sti_layer.h"
15#include "sti_vtg.h"
16
17#define ENA_COLOR_FILL BIT(8)
18#define WAIT_NEXT_VSYNC BIT(31)
19
20/* GDP color formats */
21#define GDP_RGB565 0x00
22#define GDP_RGB888 0x01
23#define GDP_RGB888_32 0x02
24#define GDP_ARGB8565 0x04
25#define GDP_ARGB8888 0x05
26#define GDP_ARGB1555 0x06
27#define GDP_ARGB4444 0x07
28#define GDP_CLUT8 0x0B
29#define GDP_YCBR888 0x10
30#define GDP_YCBR422R 0x12
31#define GDP_AYCBR8888 0x15
32
33#define GAM_GDP_CTL_OFFSET 0x00
34#define GAM_GDP_AGC_OFFSET 0x04
35#define GAM_GDP_VPO_OFFSET 0x0C
36#define GAM_GDP_VPS_OFFSET 0x10
37#define GAM_GDP_PML_OFFSET 0x14
38#define GAM_GDP_PMP_OFFSET 0x18
39#define GAM_GDP_SIZE_OFFSET 0x1C
40#define GAM_GDP_NVN_OFFSET 0x24
41#define GAM_GDP_KEY1_OFFSET 0x28
42#define GAM_GDP_KEY2_OFFSET 0x2C
43#define GAM_GDP_PPT_OFFSET 0x34
44#define GAM_GDP_CML_OFFSET 0x3C
45#define GAM_GDP_MST_OFFSET 0x68
46
47#define GAM_GDP_ALPHARANGE_255 BIT(5)
48#define GAM_GDP_AGC_FULL_RANGE 0x00808080
49#define GAM_GDP_PPT_IGNORE (BIT(1) | BIT(0))
50#define GAM_GDP_SIZE_MAX 0x7FF
51
52#define GDP_NODE_NB_BANK 2
53#define GDP_NODE_PER_FIELD 2
54
55struct sti_gdp_node {
56 u32 gam_gdp_ctl;
57 u32 gam_gdp_agc;
58 u32 reserved1;
59 u32 gam_gdp_vpo;
60 u32 gam_gdp_vps;
61 u32 gam_gdp_pml;
62 u32 gam_gdp_pmp;
63 u32 gam_gdp_size;
64 u32 reserved2;
65 u32 gam_gdp_nvn;
66 u32 gam_gdp_key1;
67 u32 gam_gdp_key2;
68 u32 reserved3;
69 u32 gam_gdp_ppt;
70 u32 reserved4;
71 u32 gam_gdp_cml;
72};
73
74struct sti_gdp_node_list {
75 struct sti_gdp_node *top_field;
76 struct sti_gdp_node *btm_field;
77};
78
79/**
80 * STI GDP structure
81 *
82 * @layer: layer structure
83 * @clk_pix: pixel clock for the current gdp
84 * @vtg_field_nb: callback for VTG FIELD (top or bottom) notification
85 * @is_curr_top: true if the current node processed is the top field
86 * @node_list: array of node list
87 */
88struct sti_gdp {
89 struct sti_layer layer;
90 struct clk *clk_pix;
91 struct notifier_block vtg_field_nb;
92 bool is_curr_top;
93 struct sti_gdp_node_list node_list[GDP_NODE_NB_BANK];
94};
95
96#define to_sti_gdp(x) container_of(x, struct sti_gdp, layer)
97
98static const uint32_t gdp_supported_formats[] = {
99 DRM_FORMAT_XRGB8888,
100 DRM_FORMAT_ARGB8888,
101 DRM_FORMAT_ARGB4444,
102 DRM_FORMAT_ARGB1555,
103 DRM_FORMAT_RGB565,
104 DRM_FORMAT_RGB888,
105 DRM_FORMAT_AYUV,
106 DRM_FORMAT_YUV444,
107 DRM_FORMAT_VYUY,
108 DRM_FORMAT_C8,
109};
110
111static const uint32_t *sti_gdp_get_formats(struct sti_layer *layer)
112{
113 return gdp_supported_formats;
114}
115
116static unsigned int sti_gdp_get_nb_formats(struct sti_layer *layer)
117{
118 return ARRAY_SIZE(gdp_supported_formats);
119}
120
121static int sti_gdp_fourcc2format(int fourcc)
122{
123 switch (fourcc) {
124 case DRM_FORMAT_XRGB8888:
125 return GDP_RGB888_32;
126 case DRM_FORMAT_ARGB8888:
127 return GDP_ARGB8888;
128 case DRM_FORMAT_ARGB4444:
129 return GDP_ARGB4444;
130 case DRM_FORMAT_ARGB1555:
131 return GDP_ARGB1555;
132 case DRM_FORMAT_RGB565:
133 return GDP_RGB565;
134 case DRM_FORMAT_RGB888:
135 return GDP_RGB888;
136 case DRM_FORMAT_AYUV:
137 return GDP_AYCBR8888;
138 case DRM_FORMAT_YUV444:
139 return GDP_YCBR888;
140 case DRM_FORMAT_VYUY:
141 return GDP_YCBR422R;
142 case DRM_FORMAT_C8:
143 return GDP_CLUT8;
144 }
145 return -1;
146}
147
148static int sti_gdp_get_alpharange(int format)
149{
150 switch (format) {
151 case GDP_ARGB8565:
152 case GDP_ARGB8888:
153 case GDP_AYCBR8888:
154 return GAM_GDP_ALPHARANGE_255;
155 }
156 return 0;
157}
158
159/**
160 * sti_gdp_get_free_nodes
161 * @layer: gdp layer
162 *
163 * Look for a GDP node list that is not currently read by the HW.
164 *
165 * RETURNS:
166 * Pointer to the free GDP node list
167 */
168static struct sti_gdp_node_list *sti_gdp_get_free_nodes(struct sti_layer *layer)
169{
170 int hw_nvn;
171 void *virt_nvn;
172 struct sti_gdp *gdp = to_sti_gdp(layer);
173 unsigned int i;
174
175 hw_nvn = readl(layer->regs + GAM_GDP_NVN_OFFSET);
176 if (!hw_nvn)
177 goto end;
178
179 virt_nvn = dma_to_virt(layer->dev, (dma_addr_t) hw_nvn);
180
181 for (i = 0; i < GDP_NODE_NB_BANK; i++)
182 if ((virt_nvn != gdp->node_list[i].btm_field) &&
183 (virt_nvn != gdp->node_list[i].top_field))
184 return &gdp->node_list[i];
185
186 /* in hazardious cases restart with the first node */
187 DRM_ERROR("inconsistent NVN for %s: 0x%08X\n",
188 sti_layer_to_str(layer), hw_nvn);
189
190end:
191 return &gdp->node_list[0];
192}
193
194/**
195 * sti_gdp_get_current_nodes
196 * @layer: GDP layer
197 *
198 * Look for GDP nodes that are currently read by the HW.
199 *
200 * RETURNS:
201 * Pointer to the current GDP node list
202 */
203static
204struct sti_gdp_node_list *sti_gdp_get_current_nodes(struct sti_layer *layer)
205{
206 int hw_nvn;
207 void *virt_nvn;
208 struct sti_gdp *gdp = to_sti_gdp(layer);
209 unsigned int i;
210
211 hw_nvn = readl(layer->regs + GAM_GDP_NVN_OFFSET);
212 if (!hw_nvn)
213 goto end;
214
215 virt_nvn = dma_to_virt(layer->dev, (dma_addr_t) hw_nvn);
216
217 for (i = 0; i < GDP_NODE_NB_BANK; i++)
218 if ((virt_nvn == gdp->node_list[i].btm_field) ||
219 (virt_nvn == gdp->node_list[i].top_field))
220 return &gdp->node_list[i];
221
222end:
223 DRM_DEBUG_DRIVER("Warning, NVN 0x%08X for %s does not match any node\n",
224 hw_nvn, sti_layer_to_str(layer));
225
226 return NULL;
227}
228
229/**
230 * sti_gdp_prepare_layer
231 * @lay: gdp layer
232 * @first_prepare: true if it is the first time this function is called
233 *
234 * Update the free GDP node list according to the layer properties.
235 *
236 * RETURNS:
237 * 0 on success.
238 */
239static int sti_gdp_prepare_layer(struct sti_layer *layer, bool first_prepare)
240{
241 struct sti_gdp_node_list *list;
242 struct sti_gdp_node *top_field, *btm_field;
243 struct drm_display_mode *mode = layer->mode;
244 struct device *dev = layer->dev;
245 struct sti_gdp *gdp = to_sti_gdp(layer);
246 struct sti_compositor *compo = dev_get_drvdata(dev);
247 int format;
248 unsigned int depth, bpp;
249 int rate = mode->clock * 1000;
250 int res;
251 u32 ydo, xdo, yds, xds;
252
253 list = sti_gdp_get_free_nodes(layer);
254 top_field = list->top_field;
255 btm_field = list->btm_field;
256
257 dev_dbg(dev, "%s %s top_node:0x%p btm_node:0x%p\n", __func__,
258 sti_layer_to_str(layer), top_field, btm_field);
259
260 /* Build the top field from layer params */
261 top_field->gam_gdp_agc = GAM_GDP_AGC_FULL_RANGE;
262 top_field->gam_gdp_ctl = WAIT_NEXT_VSYNC;
263 format = sti_gdp_fourcc2format(layer->format);
264 if (format == -1) {
265 DRM_ERROR("Format not supported by GDP %.4s\n",
266 (char *)&layer->format);
267 return 1;
268 }
269 top_field->gam_gdp_ctl |= format;
270 top_field->gam_gdp_ctl |= sti_gdp_get_alpharange(format);
271 top_field->gam_gdp_ppt &= ~GAM_GDP_PPT_IGNORE;
272
273 /* pixel memory location */
274 drm_fb_get_bpp_depth(layer->format, &depth, &bpp);
275 top_field->gam_gdp_pml = (u32) layer->paddr + layer->offsets[0];
276 top_field->gam_gdp_pml += layer->src_x * (bpp >> 3);
277 top_field->gam_gdp_pml += layer->src_y * layer->pitches[0];
278
279 /* input parameters */
280 top_field->gam_gdp_pmp = layer->pitches[0];
281 top_field->gam_gdp_size =
282 clamp_val(layer->src_h, 0, GAM_GDP_SIZE_MAX) << 16 |
283 clamp_val(layer->src_w, 0, GAM_GDP_SIZE_MAX);
284
285 /* output parameters */
286 ydo = sti_vtg_get_line_number(*mode, layer->dst_y);
287 yds = sti_vtg_get_line_number(*mode, layer->dst_y + layer->dst_h - 1);
288 xdo = sti_vtg_get_pixel_number(*mode, layer->dst_x);
289 xds = sti_vtg_get_pixel_number(*mode, layer->dst_x + layer->dst_w - 1);
290 top_field->gam_gdp_vpo = (ydo << 16) | xdo;
291 top_field->gam_gdp_vps = (yds << 16) | xds;
292
293 /* Same content and chained together */
294 memcpy(btm_field, top_field, sizeof(*btm_field));
295 top_field->gam_gdp_nvn = virt_to_dma(dev, btm_field);
296 btm_field->gam_gdp_nvn = virt_to_dma(dev, top_field);
297
298 /* Interlaced mode */
299 if (layer->mode->flags & DRM_MODE_FLAG_INTERLACE)
300 btm_field->gam_gdp_pml = top_field->gam_gdp_pml +
301 layer->pitches[0];
302
303 if (first_prepare) {
304 /* Register gdp callback */
305 if (sti_vtg_register_client(layer->mixer_id == STI_MIXER_MAIN ?
306 compo->vtg_main : compo->vtg_aux,
307 &gdp->vtg_field_nb, layer->mixer_id)) {
308 DRM_ERROR("Cannot register VTG notifier\n");
309 return 1;
310 }
311
312 /* Set and enable gdp clock */
313 if (gdp->clk_pix) {
314 res = clk_set_rate(gdp->clk_pix, rate);
315 if (res < 0) {
316 DRM_ERROR("Cannot set rate (%dHz) for gdp\n",
317 rate);
318 return 1;
319 }
320
321 if (clk_prepare_enable(gdp->clk_pix)) {
322 DRM_ERROR("Failed to prepare/enable gdp\n");
323 return 1;
324 }
325 }
326 }
327
328 return 0;
329}
330
331/**
332 * sti_gdp_commit_layer
333 * @lay: gdp layer
334 *
335 * Update the NVN field of the 'right' field of the current GDP node (being
336 * used by the HW) with the address of the updated ('free') top field GDP node.
337 * - In interlaced mode the 'right' field is the bottom field as we update
338 * frames starting from their top field
339 * - In progressive mode, we update both bottom and top fields which are
340 * equal nodes.
341 * At the next VSYNC, the updated node list will be used by the HW.
342 *
343 * RETURNS:
344 * 0 on success.
345 */
346static int sti_gdp_commit_layer(struct sti_layer *layer)
347{
348 struct sti_gdp_node_list *updated_list = sti_gdp_get_free_nodes(layer);
349 struct sti_gdp_node *updated_top_node = updated_list->top_field;
350 struct sti_gdp_node *updated_btm_node = updated_list->btm_field;
351 struct sti_gdp *gdp = to_sti_gdp(layer);
352 u32 dma_updated_top = virt_to_dma(layer->dev, updated_top_node);
353 u32 dma_updated_btm = virt_to_dma(layer->dev, updated_btm_node);
354 struct sti_gdp_node_list *curr_list = sti_gdp_get_current_nodes(layer);
355
356 dev_dbg(layer->dev, "%s %s top/btm_node:0x%p/0x%p\n", __func__,
357 sti_layer_to_str(layer),
358 updated_top_node, updated_btm_node);
359 dev_dbg(layer->dev, "Current NVN:0x%X\n",
360 readl(layer->regs + GAM_GDP_NVN_OFFSET));
361 dev_dbg(layer->dev, "Posted buff: %lx current buff: %x\n",
362 (unsigned long)layer->paddr,
363 readl(layer->regs + GAM_GDP_PML_OFFSET));
364
365 if (curr_list == NULL) {
366 /* First update or invalid node should directly write in the
367 * hw register */
368 DRM_DEBUG_DRIVER("%s first update (or invalid node)",
369 sti_layer_to_str(layer));
370
371 writel(gdp->is_curr_top == true ?
372 dma_updated_btm : dma_updated_top,
373 layer->regs + GAM_GDP_NVN_OFFSET);
374 return 0;
375 }
376
377 if (layer->mode->flags & DRM_MODE_FLAG_INTERLACE) {
378 if (gdp->is_curr_top == true) {
379 /* Do not update in the middle of the frame, but
380 * postpone the update after the bottom field has
381 * been displayed */
382 curr_list->btm_field->gam_gdp_nvn = dma_updated_top;
383 } else {
384 /* Direct update to avoid one frame delay */
385 writel(dma_updated_top,
386 layer->regs + GAM_GDP_NVN_OFFSET);
387 }
388 } else {
389 /* Direct update for progressive to avoid one frame delay */
390 writel(dma_updated_top, layer->regs + GAM_GDP_NVN_OFFSET);
391 }
392
393 return 0;
394}
395
396/**
397 * sti_gdp_disable_layer
398 * @lay: gdp layer
399 *
400 * Disable a GDP.
401 *
402 * RETURNS:
403 * 0 on success.
404 */
405static int sti_gdp_disable_layer(struct sti_layer *layer)
406{
407 unsigned int i;
408 struct sti_gdp *gdp = to_sti_gdp(layer);
409 struct sti_compositor *compo = dev_get_drvdata(layer->dev);
410
411 DRM_DEBUG_DRIVER("%s\n", sti_layer_to_str(layer));
412
413 /* Set the nodes as 'to be ignored on mixer' */
414 for (i = 0; i < GDP_NODE_NB_BANK; i++) {
415 gdp->node_list[i].top_field->gam_gdp_ppt |= GAM_GDP_PPT_IGNORE;
416 gdp->node_list[i].btm_field->gam_gdp_ppt |= GAM_GDP_PPT_IGNORE;
417 }
418
419 if (sti_vtg_unregister_client(layer->mixer_id == STI_MIXER_MAIN ?
420 compo->vtg_main : compo->vtg_aux, &gdp->vtg_field_nb))
421 DRM_DEBUG_DRIVER("Warning: cannot unregister VTG notifier\n");
422
423 if (gdp->clk_pix)
424 clk_disable_unprepare(gdp->clk_pix);
425
426 return 0;
427}
428
429/**
430 * sti_gdp_field_cb
431 * @nb: notifier block
432 * @event: event message
433 * @data: private data
434 *
435 * Handle VTG top field and bottom field event.
436 *
437 * RETURNS:
438 * 0 on success.
439 */
440int sti_gdp_field_cb(struct notifier_block *nb,
441 unsigned long event, void *data)
442{
443 struct sti_gdp *gdp = container_of(nb, struct sti_gdp, vtg_field_nb);
444
445 switch (event) {
446 case VTG_TOP_FIELD_EVENT:
447 gdp->is_curr_top = true;
448 break;
449 case VTG_BOTTOM_FIELD_EVENT:
450 gdp->is_curr_top = false;
451 break;
452 default:
453 DRM_ERROR("unsupported event: %lu\n", event);
454 break;
455 }
456
457 return 0;
458}
459
460static void sti_gdp_init(struct sti_layer *layer)
461{
462 struct sti_gdp *gdp = to_sti_gdp(layer);
463 struct device_node *np = layer->dev->of_node;
464 dma_addr_t dma;
465 void *base;
466 unsigned int i, size;
467
468 /* Allocate all the nodes within a single memory page */
469 size = sizeof(struct sti_gdp_node) *
470 GDP_NODE_PER_FIELD * GDP_NODE_NB_BANK;
471
472 base = dma_alloc_writecombine(layer->dev,
473 size, &dma, GFP_KERNEL | GFP_DMA);
474 if (!base) {
475 DRM_ERROR("Failed to allocate memory for GDP node\n");
476 return;
477 }
478 memset(base, 0, size);
479
480 for (i = 0; i < GDP_NODE_NB_BANK; i++) {
481 if (virt_to_dma(layer->dev, base) & 0xF) {
482 DRM_ERROR("Mem alignment failed\n");
483 return;
484 }
485 gdp->node_list[i].top_field = base;
486 DRM_DEBUG_DRIVER("node[%d].top_field=%p\n", i, base);
487 base += sizeof(struct sti_gdp_node);
488
489 if (virt_to_dma(layer->dev, base) & 0xF) {
490 DRM_ERROR("Mem alignment failed\n");
491 return;
492 }
493 gdp->node_list[i].btm_field = base;
494 DRM_DEBUG_DRIVER("node[%d].btm_field=%p\n", i, base);
495 base += sizeof(struct sti_gdp_node);
496 }
497
498 if (of_device_is_compatible(np, "st,stih407-compositor")) {
499 /* GDP of STiH407 chip have its own pixel clock */
500 char *clk_name;
501
502 switch (layer->desc) {
503 case STI_GDP_0:
504 clk_name = "pix_gdp1";
505 break;
506 case STI_GDP_1:
507 clk_name = "pix_gdp2";
508 break;
509 case STI_GDP_2:
510 clk_name = "pix_gdp3";
511 break;
512 case STI_GDP_3:
513 clk_name = "pix_gdp4";
514 break;
515 default:
516 DRM_ERROR("GDP id not recognized\n");
517 return;
518 }
519
520 gdp->clk_pix = devm_clk_get(layer->dev, clk_name);
521 if (IS_ERR(gdp->clk_pix))
522 DRM_ERROR("Cannot get %s clock\n", clk_name);
523 }
524}
525
526static const struct sti_layer_funcs gdp_ops = {
527 .get_formats = sti_gdp_get_formats,
528 .get_nb_formats = sti_gdp_get_nb_formats,
529 .init = sti_gdp_init,
530 .prepare = sti_gdp_prepare_layer,
531 .commit = sti_gdp_commit_layer,
532 .disable = sti_gdp_disable_layer,
533};
534
535struct sti_layer *sti_gdp_create(struct device *dev, int id)
536{
537 struct sti_gdp *gdp;
538
539 gdp = devm_kzalloc(dev, sizeof(*gdp), GFP_KERNEL);
540 if (!gdp) {
541 DRM_ERROR("Failed to allocate memory for GDP\n");
542 return NULL;
543 }
544
545 gdp->layer.ops = &gdp_ops;
546 gdp->vtg_field_nb.notifier_call = sti_gdp_field_cb;
547
548 return (struct sti_layer *)gdp;
549}
diff --git a/drivers/gpu/drm/sti/sti_gdp.h b/drivers/gpu/drm/sti/sti_gdp.h
new file mode 100644
index 000000000000..1dab68274ad3
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_gdp.h
@@ -0,0 +1,16 @@
1/*
2 * Copyright (C) STMicroelectronics SA 2014
3 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
4 * Fabien Dessenne <fabien.dessenne@st.com>
5 * for STMicroelectronics.
6 * License terms: GNU General Public License (GPL), version 2
7 */
8
9#ifndef _STI_GDP_H_
10#define _STI_GDP_H_
11
12#include <linux/types.h>
13
14struct sti_layer *sti_gdp_create(struct device *dev, int id);
15
16#endif
diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c
new file mode 100644
index 000000000000..72d957f81c05
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_hda.c
@@ -0,0 +1,794 @@
1/*
2 * Copyright (C) STMicroelectronics SA 2014
3 * Author: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
5 */
6
7#include <linux/clk.h>
8#include <linux/component.h>
9#include <linux/module.h>
10#include <linux/platform_device.h>
11
12#include <drm/drmP.h>
13#include <drm/drm_crtc_helper.h>
14
15/* HDformatter registers */
16#define HDA_ANA_CFG 0x0000
17#define HDA_ANA_SCALE_CTRL_Y 0x0004
18#define HDA_ANA_SCALE_CTRL_CB 0x0008
19#define HDA_ANA_SCALE_CTRL_CR 0x000C
20#define HDA_ANA_ANC_CTRL 0x0010
21#define HDA_ANA_SRC_Y_CFG 0x0014
22#define HDA_COEFF_Y_PH1_TAP123 0x0018
23#define HDA_COEFF_Y_PH1_TAP456 0x001C
24#define HDA_COEFF_Y_PH2_TAP123 0x0020
25#define HDA_COEFF_Y_PH2_TAP456 0x0024
26#define HDA_COEFF_Y_PH3_TAP123 0x0028
27#define HDA_COEFF_Y_PH3_TAP456 0x002C
28#define HDA_COEFF_Y_PH4_TAP123 0x0030
29#define HDA_COEFF_Y_PH4_TAP456 0x0034
30#define HDA_ANA_SRC_C_CFG 0x0040
31#define HDA_COEFF_C_PH1_TAP123 0x0044
32#define HDA_COEFF_C_PH1_TAP456 0x0048
33#define HDA_COEFF_C_PH2_TAP123 0x004C
34#define HDA_COEFF_C_PH2_TAP456 0x0050
35#define HDA_COEFF_C_PH3_TAP123 0x0054
36#define HDA_COEFF_C_PH3_TAP456 0x0058
37#define HDA_COEFF_C_PH4_TAP123 0x005C
38#define HDA_COEFF_C_PH4_TAP456 0x0060
39#define HDA_SYNC_AWGI 0x0300
40
41/* HDA_ANA_CFG */
42#define CFG_AWG_ASYNC_EN BIT(0)
43#define CFG_AWG_ASYNC_HSYNC_MTD BIT(1)
44#define CFG_AWG_ASYNC_VSYNC_MTD BIT(2)
45#define CFG_AWG_SYNC_DEL BIT(3)
46#define CFG_AWG_FLTR_MODE_SHIFT 4
47#define CFG_AWG_FLTR_MODE_MASK (0xF << CFG_AWG_FLTR_MODE_SHIFT)
48#define CFG_AWG_FLTR_MODE_SD (0 << CFG_AWG_FLTR_MODE_SHIFT)
49#define CFG_AWG_FLTR_MODE_ED (1 << CFG_AWG_FLTR_MODE_SHIFT)
50#define CFG_AWG_FLTR_MODE_HD (2 << CFG_AWG_FLTR_MODE_SHIFT)
51#define CFG_SYNC_ON_PBPR_MASK BIT(8)
52#define CFG_PREFILTER_EN_MASK BIT(9)
53#define CFG_PBPR_SYNC_OFF_SHIFT 16
54#define CFG_PBPR_SYNC_OFF_MASK (0x7FF << CFG_PBPR_SYNC_OFF_SHIFT)
55#define CFG_PBPR_SYNC_OFF_VAL 0x117 /* Voltage dependent. stiH416 */
56
57/* Default scaling values */
58#define SCALE_CTRL_Y_DFLT 0x00C50256
59#define SCALE_CTRL_CB_DFLT 0x00DB0249
60#define SCALE_CTRL_CR_DFLT 0x00DB0249
61
62/* Video DACs control */
63#define VIDEO_DACS_CONTROL_MASK 0x0FFF
64#define VIDEO_DACS_CONTROL_SYSCFG2535 0x085C /* for stih416 */
65#define DAC_CFG_HD_OFF_SHIFT 5
66#define DAC_CFG_HD_OFF_MASK (0x7 << DAC_CFG_HD_OFF_SHIFT)
67#define VIDEO_DACS_CONTROL_SYSCFG5072 0x0120 /* for stih407 */
68#define DAC_CFG_HD_HZUVW_OFF_MASK BIT(1)
69
70
71/* Upsampler values for the alternative 2X Filter */
72#define SAMPLER_COEF_NB 8
73#define HDA_ANA_SRC_Y_CFG_ALT_2X 0x01130000
74static u32 coef_y_alt_2x[] = {
75 0x00FE83FB, 0x1F900401, 0x00000000, 0x00000000,
76 0x00F408F9, 0x055F7C25, 0x00000000, 0x00000000
77};
78
79#define HDA_ANA_SRC_C_CFG_ALT_2X 0x01750004
80static u32 coef_c_alt_2x[] = {
81 0x001305F7, 0x05274BD0, 0x00000000, 0x00000000,
82 0x0004907C, 0x09C80B9D, 0x00000000, 0x00000000
83};
84
85/* Upsampler values for the 4X Filter */
86#define HDA_ANA_SRC_Y_CFG_4X 0x01ED0005
87#define HDA_ANA_SRC_C_CFG_4X 0x01ED0004
88static u32 coef_yc_4x[] = {
89 0x00FC827F, 0x008FE20B, 0x00F684FC, 0x050F7C24,
90 0x00F4857C, 0x0A1F402E, 0x00FA027F, 0x0E076E1D
91};
92
93/* AWG instructions for some video modes */
94#define AWG_MAX_INST 64
95
96/* 720p@50 */
97static u32 AWGi_720p_50[] = {
98 0x00000971, 0x00000C26, 0x0000013B, 0x00000CDA,
99 0x00000104, 0x00000E7E, 0x00000E7F, 0x0000013B,
100 0x00000D8E, 0x00000104, 0x00001804, 0x00000971,
101 0x00000C26, 0x0000003B, 0x00000FB4, 0x00000FB5,
102 0x00000104, 0x00001AE8
103};
104
105#define NN_720p_50 ARRAY_SIZE(AWGi_720p_50)
106
107/* 720p@60 */
108static u32 AWGi_720p_60[] = {
109 0x00000971, 0x00000C26, 0x0000013B, 0x00000CDA,
110 0x00000104, 0x00000E7E, 0x00000E7F, 0x0000013B,
111 0x00000C44, 0x00000104, 0x00001804, 0x00000971,
112 0x00000C26, 0x0000003B, 0x00000F0F, 0x00000F10,
113 0x00000104, 0x00001AE8
114};
115
116#define NN_720p_60 ARRAY_SIZE(AWGi_720p_60)
117
118/* 1080p@30 */
119static u32 AWGi_1080p_30[] = {
120 0x00000971, 0x00000C2A, 0x0000013B, 0x00000C56,
121 0x00000104, 0x00000FDC, 0x00000FDD, 0x0000013B,
122 0x00000C2A, 0x00000104, 0x00001804, 0x00000971,
123 0x00000C2A, 0x0000003B, 0x00000EBE, 0x00000EBF,
124 0x00000EBF, 0x00000104, 0x00001A2F, 0x00001C4B,
125 0x00001C52
126};
127
128#define NN_1080p_30 ARRAY_SIZE(AWGi_1080p_30)
129
130/* 1080p@25 */
131static u32 AWGi_1080p_25[] = {
132 0x00000971, 0x00000C2A, 0x0000013B, 0x00000C56,
133 0x00000104, 0x00000FDC, 0x00000FDD, 0x0000013B,
134 0x00000DE2, 0x00000104, 0x00001804, 0x00000971,
135 0x00000C2A, 0x0000003B, 0x00000F51, 0x00000F51,
136 0x00000F52, 0x00000104, 0x00001A2F, 0x00001C4B,
137 0x00001C52
138};
139
140#define NN_1080p_25 ARRAY_SIZE(AWGi_1080p_25)
141
142/* 1080p@24 */
143static u32 AWGi_1080p_24[] = {
144 0x00000971, 0x00000C2A, 0x0000013B, 0x00000C56,
145 0x00000104, 0x00000FDC, 0x00000FDD, 0x0000013B,
146 0x00000E50, 0x00000104, 0x00001804, 0x00000971,
147 0x00000C2A, 0x0000003B, 0x00000F76, 0x00000F76,
148 0x00000F76, 0x00000104, 0x00001A2F, 0x00001C4B,
149 0x00001C52
150};
151
152#define NN_1080p_24 ARRAY_SIZE(AWGi_1080p_24)
153
154/* 720x480p@60 */
155static u32 AWGi_720x480p_60[] = {
156 0x00000904, 0x00000F18, 0x0000013B, 0x00001805,
157 0x00000904, 0x00000C3D, 0x0000003B, 0x00001A06
158};
159
160#define NN_720x480p_60 ARRAY_SIZE(AWGi_720x480p_60)
161
162/* Video mode category */
163enum sti_hda_vid_cat {
164 VID_SD,
165 VID_ED,
166 VID_HD_74M,
167 VID_HD_148M
168};
169
170struct sti_hda_video_config {
171 struct drm_display_mode mode;
172 u32 *awg_instr;
173 int nb_instr;
174 enum sti_hda_vid_cat vid_cat;
175};
176
177/* HD analog supported modes
178 * Interlaced modes may be added when supported by the whole display chain
179 */
180static const struct sti_hda_video_config hda_supported_modes[] = {
181 /* 1080p30 74.250Mhz */
182 {{DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008,
183 2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
184 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC)},
185 AWGi_1080p_30, NN_1080p_30, VID_HD_74M},
186 /* 1080p30 74.176Mhz */
187 {{DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74176, 1920, 2008,
188 2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
189 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC)},
190 AWGi_1080p_30, NN_1080p_30, VID_HD_74M},
191 /* 1080p24 74.250Mhz */
192 {{DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2558,
193 2602, 2750, 0, 1080, 1084, 1089, 1125, 0,
194 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC)},
195 AWGi_1080p_24, NN_1080p_24, VID_HD_74M},
196 /* 1080p24 74.176Mhz */
197 {{DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74176, 1920, 2558,
198 2602, 2750, 0, 1080, 1084, 1089, 1125, 0,
199 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC)},
200 AWGi_1080p_24, NN_1080p_24, VID_HD_74M},
201 /* 1080p25 74.250Mhz */
202 {{DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448,
203 2492, 2640, 0, 1080, 1084, 1089, 1125, 0,
204 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC)},
205 AWGi_1080p_25, NN_1080p_25, VID_HD_74M},
206 /* 720p60 74.250Mhz */
207 {{DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1390,
208 1430, 1650, 0, 720, 725, 730, 750, 0,
209 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC)},
210 AWGi_720p_60, NN_720p_60, VID_HD_74M},
211 /* 720p60 74.176Mhz */
212 {{DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74176, 1280, 1390,
213 1430, 1650, 0, 720, 725, 730, 750, 0,
214 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC)},
215 AWGi_720p_60, NN_720p_60, VID_HD_74M},
216 /* 720p50 74.250Mhz */
217 {{DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1720,
218 1760, 1980, 0, 720, 725, 730, 750, 0,
219 DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC)},
220 AWGi_720p_50, NN_720p_50, VID_HD_74M},
221 /* 720x480p60 27.027Mhz */
222 {{DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27027, 720, 736,
223 798, 858, 0, 480, 489, 495, 525, 0,
224 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC)},
225 AWGi_720x480p_60, NN_720x480p_60, VID_ED},
226 /* 720x480p60 27.000Mhz */
227 {{DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736,
228 798, 858, 0, 480, 489, 495, 525, 0,
229 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC)},
230 AWGi_720x480p_60, NN_720x480p_60, VID_ED}
231};
232
233/**
234 * STI hd analog structure
235 *
236 * @dev: driver device
237 * @drm_dev: pointer to drm device
238 * @mode: current display mode selected
239 * @regs: HD analog register
240 * @video_dacs_ctrl: video DACS control register
241 * @enabled: true if HD analog is enabled else false
242 */
243struct sti_hda {
244 struct device dev;
245 struct drm_device *drm_dev;
246 struct drm_display_mode mode;
247 void __iomem *regs;
248 void __iomem *video_dacs_ctrl;
249 struct clk *clk_pix;
250 struct clk *clk_hddac;
251 bool enabled;
252};
253
254struct sti_hda_connector {
255 struct drm_connector drm_connector;
256 struct drm_encoder *encoder;
257 struct sti_hda *hda;
258};
259
260#define to_sti_hda_connector(x) \
261 container_of(x, struct sti_hda_connector, drm_connector)
262
263static u32 hda_read(struct sti_hda *hda, int offset)
264{
265 return readl(hda->regs + offset);
266}
267
268static void hda_write(struct sti_hda *hda, u32 val, int offset)
269{
270 writel(val, hda->regs + offset);
271}
272
273/**
274 * Search for a video mode in the supported modes table
275 *
276 * @mode: mode being searched
277 * @idx: index of the found mode
278 *
279 * Return true if mode is found
280 */
281static bool hda_get_mode_idx(struct drm_display_mode mode, int *idx)
282{
283 unsigned int i;
284
285 for (i = 0; i < ARRAY_SIZE(hda_supported_modes); i++)
286 if (drm_mode_equal(&hda_supported_modes[i].mode, &mode)) {
287 *idx = i;
288 return true;
289 }
290 return false;
291}
292
293/**
294 * Enable the HD DACS
295 *
296 * @hda: pointer to HD analog structure
297 * @enable: true if HD DACS need to be enabled, else false
298 */
299static void hda_enable_hd_dacs(struct sti_hda *hda, bool enable)
300{
301 u32 mask;
302
303 if (hda->video_dacs_ctrl) {
304 u32 val;
305
306 switch ((u32)hda->video_dacs_ctrl & VIDEO_DACS_CONTROL_MASK) {
307 case VIDEO_DACS_CONTROL_SYSCFG2535:
308 mask = DAC_CFG_HD_OFF_MASK;
309 break;
310 case VIDEO_DACS_CONTROL_SYSCFG5072:
311 mask = DAC_CFG_HD_HZUVW_OFF_MASK;
312 break;
313 default:
314 DRM_INFO("Video DACS control register not supported!");
315 return;
316 }
317
318 val = readl(hda->video_dacs_ctrl);
319 if (enable)
320 val &= ~mask;
321 else
322 val |= mask;
323
324 writel(val, hda->video_dacs_ctrl);
325 }
326}
327
328/**
329 * Configure AWG, writing instructions
330 *
331 * @hda: pointer to HD analog structure
332 * @awg_instr: pointer to AWG instructions table
333 * @nb: nb of AWG instructions
334 */
335static void sti_hda_configure_awg(struct sti_hda *hda, u32 *awg_instr, int nb)
336{
337 unsigned int i;
338
339 DRM_DEBUG_DRIVER("\n");
340
341 for (i = 0; i < nb; i++)
342 hda_write(hda, awg_instr[i], HDA_SYNC_AWGI + i * 4);
343 for (i = nb; i < AWG_MAX_INST; i++)
344 hda_write(hda, 0, HDA_SYNC_AWGI + i * 4);
345}
346
347static void sti_hda_disable(struct drm_bridge *bridge)
348{
349 struct sti_hda *hda = bridge->driver_private;
350 u32 val;
351
352 if (!hda->enabled)
353 return;
354
355 DRM_DEBUG_DRIVER("\n");
356
357 /* Disable HD DAC and AWG */
358 val = hda_read(hda, HDA_ANA_CFG);
359 val &= ~CFG_AWG_ASYNC_EN;
360 hda_write(hda, val, HDA_ANA_CFG);
361 hda_write(hda, 0, HDA_ANA_ANC_CTRL);
362
363 hda_enable_hd_dacs(hda, false);
364
365 /* Disable/unprepare hda clock */
366 clk_disable_unprepare(hda->clk_hddac);
367 clk_disable_unprepare(hda->clk_pix);
368
369 hda->enabled = false;
370}
371
372static void sti_hda_pre_enable(struct drm_bridge *bridge)
373{
374 struct sti_hda *hda = bridge->driver_private;
375 u32 val, i, mode_idx;
376 u32 src_filter_y, src_filter_c;
377 u32 *coef_y, *coef_c;
378 u32 filter_mode;
379
380 DRM_DEBUG_DRIVER("\n");
381
382 if (hda->enabled)
383 return;
384
385 /* Prepare/enable clocks */
386 if (clk_prepare_enable(hda->clk_pix))
387 DRM_ERROR("Failed to prepare/enable hda_pix clk\n");
388 if (clk_prepare_enable(hda->clk_hddac))
389 DRM_ERROR("Failed to prepare/enable hda_hddac clk\n");
390
391 if (!hda_get_mode_idx(hda->mode, &mode_idx)) {
392 DRM_ERROR("Undefined mode\n");
393 return;
394 }
395
396 switch (hda_supported_modes[mode_idx].vid_cat) {
397 case VID_HD_148M:
398 DRM_ERROR("Beyond HD analog capabilities\n");
399 return;
400 case VID_HD_74M:
401 /* HD use alternate 2x filter */
402 filter_mode = CFG_AWG_FLTR_MODE_HD;
403 src_filter_y = HDA_ANA_SRC_Y_CFG_ALT_2X;
404 src_filter_c = HDA_ANA_SRC_C_CFG_ALT_2X;
405 coef_y = coef_y_alt_2x;
406 coef_c = coef_c_alt_2x;
407 break;
408 case VID_ED:
409 /* ED uses 4x filter */
410 filter_mode = CFG_AWG_FLTR_MODE_ED;
411 src_filter_y = HDA_ANA_SRC_Y_CFG_4X;
412 src_filter_c = HDA_ANA_SRC_C_CFG_4X;
413 coef_y = coef_yc_4x;
414 coef_c = coef_yc_4x;
415 break;
416 case VID_SD:
417 DRM_ERROR("Not supported\n");
418 return;
419 default:
420 DRM_ERROR("Undefined resolution\n");
421 return;
422 }
423 DRM_DEBUG_DRIVER("Using HDA mode #%d\n", mode_idx);
424
425 /* Enable HD Video DACs */
426 hda_enable_hd_dacs(hda, true);
427
428 /* Configure scaler */
429 hda_write(hda, SCALE_CTRL_Y_DFLT, HDA_ANA_SCALE_CTRL_Y);
430 hda_write(hda, SCALE_CTRL_CB_DFLT, HDA_ANA_SCALE_CTRL_CB);
431 hda_write(hda, SCALE_CTRL_CR_DFLT, HDA_ANA_SCALE_CTRL_CR);
432
433 /* Configure sampler */
434 hda_write(hda , src_filter_y, HDA_ANA_SRC_Y_CFG);
435 hda_write(hda, src_filter_c, HDA_ANA_SRC_C_CFG);
436 for (i = 0; i < SAMPLER_COEF_NB; i++) {
437 hda_write(hda, coef_y[i], HDA_COEFF_Y_PH1_TAP123 + i * 4);
438 hda_write(hda, coef_c[i], HDA_COEFF_C_PH1_TAP123 + i * 4);
439 }
440
441 /* Configure main HDFormatter */
442 val = 0;
443 val |= (hda->mode.flags & DRM_MODE_FLAG_INTERLACE) ?
444 0 : CFG_AWG_ASYNC_VSYNC_MTD;
445 val |= (CFG_PBPR_SYNC_OFF_VAL << CFG_PBPR_SYNC_OFF_SHIFT);
446 val |= filter_mode;
447 hda_write(hda, val, HDA_ANA_CFG);
448
449 /* Configure AWG */
450 sti_hda_configure_awg(hda, hda_supported_modes[mode_idx].awg_instr,
451 hda_supported_modes[mode_idx].nb_instr);
452
453 /* Enable AWG */
454 val = hda_read(hda, HDA_ANA_CFG);
455 val |= CFG_AWG_ASYNC_EN;
456 hda_write(hda, val, HDA_ANA_CFG);
457
458 hda->enabled = true;
459}
460
461static void sti_hda_set_mode(struct drm_bridge *bridge,
462 struct drm_display_mode *mode,
463 struct drm_display_mode *adjusted_mode)
464{
465 struct sti_hda *hda = bridge->driver_private;
466 u32 mode_idx;
467 int hddac_rate;
468 int ret;
469
470 DRM_DEBUG_DRIVER("\n");
471
472 memcpy(&hda->mode, mode, sizeof(struct drm_display_mode));
473
474 if (!hda_get_mode_idx(hda->mode, &mode_idx)) {
475 DRM_ERROR("Undefined mode\n");
476 return;
477 }
478
479 switch (hda_supported_modes[mode_idx].vid_cat) {
480 case VID_HD_74M:
481 /* HD use alternate 2x filter */
482 hddac_rate = mode->clock * 1000 * 2;
483 break;
484 case VID_ED:
485 /* ED uses 4x filter */
486 hddac_rate = mode->clock * 1000 * 4;
487 break;
488 default:
489 DRM_ERROR("Undefined mode\n");
490 return;
491 }
492
493 /* HD DAC = 148.5Mhz or 108 Mhz */
494 ret = clk_set_rate(hda->clk_hddac, hddac_rate);
495 if (ret < 0)
496 DRM_ERROR("Cannot set rate (%dHz) for hda_hddac clk\n",
497 hddac_rate);
498
499 /* HDformatter clock = compositor clock */
500 ret = clk_set_rate(hda->clk_pix, mode->clock * 1000);
501 if (ret < 0)
502 DRM_ERROR("Cannot set rate (%dHz) for hda_pix clk\n",
503 mode->clock * 1000);
504}
505
506static void sti_hda_bridge_nope(struct drm_bridge *bridge)
507{
508 /* do nothing */
509}
510
511static void sti_hda_brigde_destroy(struct drm_bridge *bridge)
512{
513 drm_bridge_cleanup(bridge);
514 kfree(bridge);
515}
516
517static const struct drm_bridge_funcs sti_hda_bridge_funcs = {
518 .pre_enable = sti_hda_pre_enable,
519 .enable = sti_hda_bridge_nope,
520 .disable = sti_hda_disable,
521 .post_disable = sti_hda_bridge_nope,
522 .mode_set = sti_hda_set_mode,
523 .destroy = sti_hda_brigde_destroy,
524};
525
526static int sti_hda_connector_get_modes(struct drm_connector *connector)
527{
528 unsigned int i;
529 int count = 0;
530 struct sti_hda_connector *hda_connector
531 = to_sti_hda_connector(connector);
532 struct sti_hda *hda = hda_connector->hda;
533
534 DRM_DEBUG_DRIVER("\n");
535
536 for (i = 0; i < ARRAY_SIZE(hda_supported_modes); i++) {
537 struct drm_display_mode *mode =
538 drm_mode_duplicate(hda->drm_dev,
539 &hda_supported_modes[i].mode);
540 if (!mode)
541 continue;
542 mode->vrefresh = drm_mode_vrefresh(mode);
543
544 /* the first mode is the preferred mode */
545 if (i == 0)
546 mode->type |= DRM_MODE_TYPE_PREFERRED;
547
548 drm_mode_probed_add(connector, mode);
549 count++;
550 }
551
552 drm_mode_sort(&connector->modes);
553
554 return count;
555}
556
557#define CLK_TOLERANCE_HZ 50
558
559static int sti_hda_connector_mode_valid(struct drm_connector *connector,
560 struct drm_display_mode *mode)
561{
562 int target = mode->clock * 1000;
563 int target_min = target - CLK_TOLERANCE_HZ;
564 int target_max = target + CLK_TOLERANCE_HZ;
565 int result;
566 int idx;
567 struct sti_hda_connector *hda_connector
568 = to_sti_hda_connector(connector);
569 struct sti_hda *hda = hda_connector->hda;
570
571 if (!hda_get_mode_idx(*mode, &idx)) {
572 return MODE_BAD;
573 } else {
574 result = clk_round_rate(hda->clk_pix, target);
575
576 DRM_DEBUG_DRIVER("target rate = %d => available rate = %d\n",
577 target, result);
578
579 if ((result < target_min) || (result > target_max)) {
580 DRM_DEBUG_DRIVER("hda pixclk=%d not supported\n",
581 target);
582 return MODE_BAD;
583 }
584 }
585
586 return MODE_OK;
587}
588
589struct drm_encoder *sti_hda_best_encoder(struct drm_connector *connector)
590{
591 struct sti_hda_connector *hda_connector
592 = to_sti_hda_connector(connector);
593
594 /* Best encoder is the one associated during connector creation */
595 return hda_connector->encoder;
596}
597
598static struct drm_connector_helper_funcs sti_hda_connector_helper_funcs = {
599 .get_modes = sti_hda_connector_get_modes,
600 .mode_valid = sti_hda_connector_mode_valid,
601 .best_encoder = sti_hda_best_encoder,
602};
603
604static enum drm_connector_status
605sti_hda_connector_detect(struct drm_connector *connector, bool force)
606{
607 return connector_status_connected;
608}
609
610static void sti_hda_connector_destroy(struct drm_connector *connector)
611{
612 struct sti_hda_connector *hda_connector
613 = to_sti_hda_connector(connector);
614
615 drm_connector_unregister(connector);
616 drm_connector_cleanup(connector);
617 kfree(hda_connector);
618}
619
620static struct drm_connector_funcs sti_hda_connector_funcs = {
621 .dpms = drm_helper_connector_dpms,
622 .fill_modes = drm_helper_probe_single_connector_modes,
623 .detect = sti_hda_connector_detect,
624 .destroy = sti_hda_connector_destroy,
625};
626
627static struct drm_encoder *sti_hda_find_encoder(struct drm_device *dev)
628{
629 struct drm_encoder *encoder;
630
631 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
632 if (encoder->encoder_type == DRM_MODE_ENCODER_DAC)
633 return encoder;
634 }
635
636 return NULL;
637}
638
639static int sti_hda_bind(struct device *dev, struct device *master, void *data)
640{
641 struct sti_hda *hda = dev_get_drvdata(dev);
642 struct drm_device *drm_dev = data;
643 struct drm_encoder *encoder;
644 struct sti_hda_connector *connector;
645 struct drm_connector *drm_connector;
646 struct drm_bridge *bridge;
647 int err;
648
649 /* Set the drm device handle */
650 hda->drm_dev = drm_dev;
651
652 encoder = sti_hda_find_encoder(drm_dev);
653 if (!encoder)
654 return -ENOMEM;
655
656 connector = devm_kzalloc(dev, sizeof(*connector), GFP_KERNEL);
657 if (!connector)
658 return -ENOMEM;
659
660 connector->hda = hda;
661
662 bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL);
663 if (!bridge)
664 return -ENOMEM;
665
666 bridge->driver_private = hda;
667 drm_bridge_init(drm_dev, bridge, &sti_hda_bridge_funcs);
668
669 encoder->bridge = bridge;
670 connector->encoder = encoder;
671
672 drm_connector = (struct drm_connector *)connector;
673
674 drm_connector->polled = DRM_CONNECTOR_POLL_HPD;
675
676 drm_connector_init(drm_dev, drm_connector,
677 &sti_hda_connector_funcs, DRM_MODE_CONNECTOR_Component);
678 drm_connector_helper_add(drm_connector,
679 &sti_hda_connector_helper_funcs);
680
681 err = drm_connector_register(drm_connector);
682 if (err)
683 goto err_connector;
684
685 err = drm_mode_connector_attach_encoder(drm_connector, encoder);
686 if (err) {
687 DRM_ERROR("Failed to attach a connector to a encoder\n");
688 goto err_sysfs;
689 }
690
691 return 0;
692
693err_sysfs:
694 drm_connector_unregister(drm_connector);
695err_connector:
696 drm_bridge_cleanup(bridge);
697 drm_connector_cleanup(drm_connector);
698 return -EINVAL;
699}
700
701static void sti_hda_unbind(struct device *dev,
702 struct device *master, void *data)
703{
704 /* do nothing */
705}
706
707static const struct component_ops sti_hda_ops = {
708 .bind = sti_hda_bind,
709 .unbind = sti_hda_unbind,
710};
711
712static int sti_hda_probe(struct platform_device *pdev)
713{
714 struct device *dev = &pdev->dev;
715 struct sti_hda *hda;
716 struct resource *res;
717
718 DRM_INFO("%s\n", __func__);
719
720 hda = devm_kzalloc(dev, sizeof(*hda), GFP_KERNEL);
721 if (!hda)
722 return -ENOMEM;
723
724 hda->dev = pdev->dev;
725
726 /* Get resources */
727 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hda-reg");
728 if (!res) {
729 DRM_ERROR("Invalid hda resource\n");
730 return -ENOMEM;
731 }
732 hda->regs = devm_ioremap_nocache(dev, res->start, resource_size(res));
733 if (IS_ERR(hda->regs))
734 return PTR_ERR(hda->regs);
735
736 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
737 "video-dacs-ctrl");
738 if (res) {
739 hda->video_dacs_ctrl = devm_ioremap_nocache(dev, res->start,
740 resource_size(res));
741 if (IS_ERR(hda->video_dacs_ctrl))
742 return PTR_ERR(hda->video_dacs_ctrl);
743 } else {
744 /* If no existing video-dacs-ctrl resource continue the probe */
745 DRM_DEBUG_DRIVER("No video-dacs-ctrl resource\n");
746 hda->video_dacs_ctrl = NULL;
747 }
748
749 /* Get clock resources */
750 hda->clk_pix = devm_clk_get(dev, "pix");
751 if (IS_ERR(hda->clk_pix)) {
752 DRM_ERROR("Cannot get hda_pix clock\n");
753 return PTR_ERR(hda->clk_pix);
754 }
755
756 hda->clk_hddac = devm_clk_get(dev, "hddac");
757 if (IS_ERR(hda->clk_hddac)) {
758 DRM_ERROR("Cannot get hda_hddac clock\n");
759 return PTR_ERR(hda->clk_hddac);
760 }
761
762 platform_set_drvdata(pdev, hda);
763
764 return component_add(&pdev->dev, &sti_hda_ops);
765}
766
767static int sti_hda_remove(struct platform_device *pdev)
768{
769 component_del(&pdev->dev, &sti_hda_ops);
770 return 0;
771}
772
773static struct of_device_id hda_of_match[] = {
774 { .compatible = "st,stih416-hda", },
775 { .compatible = "st,stih407-hda", },
776 { /* end node */ }
777};
778MODULE_DEVICE_TABLE(of, hda_of_match);
779
780struct platform_driver sti_hda_driver = {
781 .driver = {
782 .name = "sti-hda",
783 .owner = THIS_MODULE,
784 .of_match_table = hda_of_match,
785 },
786 .probe = sti_hda_probe,
787 .remove = sti_hda_remove,
788};
789
790module_platform_driver(sti_hda_driver);
791
792MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
793MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
794MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c
new file mode 100644
index 000000000000..284e541d970d
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_hdmi.c
@@ -0,0 +1,810 @@
1/*
2 * Copyright (C) STMicroelectronics SA 2014
3 * Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
5 */
6
7#include <linux/clk.h>
8#include <linux/component.h>
9#include <linux/hdmi.h>
10#include <linux/module.h>
11#include <linux/of_gpio.h>
12#include <linux/platform_device.h>
13#include <linux/reset.h>
14
15#include <drm/drmP.h>
16#include <drm/drm_crtc_helper.h>
17#include <drm/drm_edid.h>
18
19#include "sti_hdmi.h"
20#include "sti_hdmi_tx3g4c28phy.h"
21#include "sti_hdmi_tx3g0c55phy.h"
22#include "sti_vtg.h"
23
24#define HDMI_CFG 0x0000
25#define HDMI_INT_EN 0x0004
26#define HDMI_INT_STA 0x0008
27#define HDMI_INT_CLR 0x000C
28#define HDMI_STA 0x0010
29#define HDMI_ACTIVE_VID_XMIN 0x0100
30#define HDMI_ACTIVE_VID_XMAX 0x0104
31#define HDMI_ACTIVE_VID_YMIN 0x0108
32#define HDMI_ACTIVE_VID_YMAX 0x010C
33#define HDMI_DFLT_CHL0_DAT 0x0110
34#define HDMI_DFLT_CHL1_DAT 0x0114
35#define HDMI_DFLT_CHL2_DAT 0x0118
36#define HDMI_SW_DI_1_HEAD_WORD 0x0210
37#define HDMI_SW_DI_1_PKT_WORD0 0x0214
38#define HDMI_SW_DI_1_PKT_WORD1 0x0218
39#define HDMI_SW_DI_1_PKT_WORD2 0x021C
40#define HDMI_SW_DI_1_PKT_WORD3 0x0220
41#define HDMI_SW_DI_1_PKT_WORD4 0x0224
42#define HDMI_SW_DI_1_PKT_WORD5 0x0228
43#define HDMI_SW_DI_1_PKT_WORD6 0x022C
44#define HDMI_SW_DI_CFG 0x0230
45
46#define HDMI_IFRAME_SLOT_AVI 1
47
48#define XCAT(prefix, x, suffix) prefix ## x ## suffix
49#define HDMI_SW_DI_N_HEAD_WORD(x) XCAT(HDMI_SW_DI_, x, _HEAD_WORD)
50#define HDMI_SW_DI_N_PKT_WORD0(x) XCAT(HDMI_SW_DI_, x, _PKT_WORD0)
51#define HDMI_SW_DI_N_PKT_WORD1(x) XCAT(HDMI_SW_DI_, x, _PKT_WORD1)
52#define HDMI_SW_DI_N_PKT_WORD2(x) XCAT(HDMI_SW_DI_, x, _PKT_WORD2)
53#define HDMI_SW_DI_N_PKT_WORD3(x) XCAT(HDMI_SW_DI_, x, _PKT_WORD3)
54#define HDMI_SW_DI_N_PKT_WORD4(x) XCAT(HDMI_SW_DI_, x, _PKT_WORD4)
55#define HDMI_SW_DI_N_PKT_WORD5(x) XCAT(HDMI_SW_DI_, x, _PKT_WORD5)
56#define HDMI_SW_DI_N_PKT_WORD6(x) XCAT(HDMI_SW_DI_, x, _PKT_WORD6)
57
58#define HDMI_IFRAME_DISABLED 0x0
59#define HDMI_IFRAME_SINGLE_SHOT 0x1
60#define HDMI_IFRAME_FIELD 0x2
61#define HDMI_IFRAME_FRAME 0x3
62#define HDMI_IFRAME_MASK 0x3
63#define HDMI_IFRAME_CFG_DI_N(x, n) ((x) << ((n-1)*4)) /* n from 1 to 6 */
64
65#define HDMI_CFG_DEVICE_EN BIT(0)
66#define HDMI_CFG_HDMI_NOT_DVI BIT(1)
67#define HDMI_CFG_HDCP_EN BIT(2)
68#define HDMI_CFG_ESS_NOT_OESS BIT(3)
69#define HDMI_CFG_H_SYNC_POL_NEG BIT(4)
70#define HDMI_CFG_SINK_TERM_DET_EN BIT(5)
71#define HDMI_CFG_V_SYNC_POL_NEG BIT(6)
72#define HDMI_CFG_422_EN BIT(8)
73#define HDMI_CFG_FIFO_OVERRUN_CLR BIT(12)
74#define HDMI_CFG_FIFO_UNDERRUN_CLR BIT(13)
75#define HDMI_CFG_SW_RST_EN BIT(31)
76
77#define HDMI_INT_GLOBAL BIT(0)
78#define HDMI_INT_SW_RST BIT(1)
79#define HDMI_INT_PIX_CAP BIT(3)
80#define HDMI_INT_HOT_PLUG BIT(4)
81#define HDMI_INT_DLL_LCK BIT(5)
82#define HDMI_INT_NEW_FRAME BIT(6)
83#define HDMI_INT_GENCTRL_PKT BIT(7)
84#define HDMI_INT_SINK_TERM_PRESENT BIT(11)
85
86#define HDMI_DEFAULT_INT (HDMI_INT_SINK_TERM_PRESENT \
87 | HDMI_INT_DLL_LCK \
88 | HDMI_INT_HOT_PLUG \
89 | HDMI_INT_GLOBAL)
90
91#define HDMI_WORKING_INT (HDMI_INT_SINK_TERM_PRESENT \
92 | HDMI_INT_GENCTRL_PKT \
93 | HDMI_INT_NEW_FRAME \
94 | HDMI_INT_DLL_LCK \
95 | HDMI_INT_HOT_PLUG \
96 | HDMI_INT_PIX_CAP \
97 | HDMI_INT_SW_RST \
98 | HDMI_INT_GLOBAL)
99
100#define HDMI_STA_SW_RST BIT(1)
101
102struct sti_hdmi_connector {
103 struct drm_connector drm_connector;
104 struct drm_encoder *encoder;
105 struct sti_hdmi *hdmi;
106};
107
108#define to_sti_hdmi_connector(x) \
109 container_of(x, struct sti_hdmi_connector, drm_connector)
110
111u32 hdmi_read(struct sti_hdmi *hdmi, int offset)
112{
113 return readl(hdmi->regs + offset);
114}
115
116void hdmi_write(struct sti_hdmi *hdmi, u32 val, int offset)
117{
118 writel(val, hdmi->regs + offset);
119}
120
121/**
122 * HDMI interrupt handler threaded
123 *
124 * @irq: irq number
125 * @arg: connector structure
126 */
127static irqreturn_t hdmi_irq_thread(int irq, void *arg)
128{
129 struct sti_hdmi *hdmi = arg;
130
131 /* Hot plug/unplug IRQ */
132 if (hdmi->irq_status & HDMI_INT_HOT_PLUG) {
133 /* read gpio to get the status */
134 hdmi->hpd = gpio_get_value(hdmi->hpd_gpio);
135 if (hdmi->drm_dev)
136 drm_helper_hpd_irq_event(hdmi->drm_dev);
137 }
138
139 /* Sw reset and PLL lock are exclusive so we can use the same
140 * event to signal them
141 */
142 if (hdmi->irq_status & (HDMI_INT_SW_RST | HDMI_INT_DLL_LCK)) {
143 hdmi->event_received = true;
144 wake_up_interruptible(&hdmi->wait_event);
145 }
146
147 return IRQ_HANDLED;
148}
149
150/**
151 * HDMI interrupt handler
152 *
153 * @irq: irq number
154 * @arg: connector structure
155 */
156static irqreturn_t hdmi_irq(int irq, void *arg)
157{
158 struct sti_hdmi *hdmi = arg;
159
160 /* read interrupt status */
161 hdmi->irq_status = hdmi_read(hdmi, HDMI_INT_STA);
162
163 /* clear interrupt status */
164 hdmi_write(hdmi, hdmi->irq_status, HDMI_INT_CLR);
165
166 /* force sync bus write */
167 hdmi_read(hdmi, HDMI_INT_STA);
168
169 return IRQ_WAKE_THREAD;
170}
171
172/**
173 * Set hdmi active area depending on the drm display mode selected
174 *
175 * @hdmi: pointer on the hdmi internal structure
176 */
177static void hdmi_active_area(struct sti_hdmi *hdmi)
178{
179 u32 xmin, xmax;
180 u32 ymin, ymax;
181
182 xmin = sti_vtg_get_pixel_number(hdmi->mode, 0);
183 xmax = sti_vtg_get_pixel_number(hdmi->mode, hdmi->mode.hdisplay - 1);
184 ymin = sti_vtg_get_line_number(hdmi->mode, 0);
185 ymax = sti_vtg_get_line_number(hdmi->mode, hdmi->mode.vdisplay - 1);
186
187 hdmi_write(hdmi, xmin, HDMI_ACTIVE_VID_XMIN);
188 hdmi_write(hdmi, xmax, HDMI_ACTIVE_VID_XMAX);
189 hdmi_write(hdmi, ymin, HDMI_ACTIVE_VID_YMIN);
190 hdmi_write(hdmi, ymax, HDMI_ACTIVE_VID_YMAX);
191}
192
193/**
194 * Overall hdmi configuration
195 *
196 * @hdmi: pointer on the hdmi internal structure
197 */
198static void hdmi_config(struct sti_hdmi *hdmi)
199{
200 u32 conf;
201
202 DRM_DEBUG_DRIVER("\n");
203
204 /* Clear overrun and underrun fifo */
205 conf = HDMI_CFG_FIFO_OVERRUN_CLR | HDMI_CFG_FIFO_UNDERRUN_CLR;
206
207 /* Enable HDMI mode not DVI */
208 conf |= HDMI_CFG_HDMI_NOT_DVI | HDMI_CFG_ESS_NOT_OESS;
209
210 /* Enable sink term detection */
211 conf |= HDMI_CFG_SINK_TERM_DET_EN;
212
213 /* Set Hsync polarity */
214 if (hdmi->mode.flags & DRM_MODE_FLAG_NHSYNC) {
215 DRM_DEBUG_DRIVER("H Sync Negative\n");
216 conf |= HDMI_CFG_H_SYNC_POL_NEG;
217 }
218
219 /* Set Vsync polarity */
220 if (hdmi->mode.flags & DRM_MODE_FLAG_NVSYNC) {
221 DRM_DEBUG_DRIVER("V Sync Negative\n");
222 conf |= HDMI_CFG_V_SYNC_POL_NEG;
223 }
224
225 /* Enable HDMI */
226 conf |= HDMI_CFG_DEVICE_EN;
227
228 hdmi_write(hdmi, conf, HDMI_CFG);
229}
230
231/**
232 * Prepare and configure the AVI infoframe
233 *
234 * AVI infoframe are transmitted at least once per two video field and
235 * contains information about HDMI transmission mode such as color space,
236 * colorimetry, ...
237 *
238 * @hdmi: pointer on the hdmi internal structure
239 *
240 * Return negative value if error occurs
241 */
242static int hdmi_avi_infoframe_config(struct sti_hdmi *hdmi)
243{
244 struct drm_display_mode *mode = &hdmi->mode;
245 struct hdmi_avi_infoframe infoframe;
246 u8 buffer[HDMI_INFOFRAME_SIZE(AVI)];
247 u8 *frame = buffer + HDMI_INFOFRAME_HEADER_SIZE;
248 u32 val;
249 int ret;
250
251 DRM_DEBUG_DRIVER("\n");
252
253 ret = drm_hdmi_avi_infoframe_from_display_mode(&infoframe, mode);
254 if (ret < 0) {
255 DRM_ERROR("failed to setup AVI infoframe: %d\n", ret);
256 return ret;
257 }
258
259 /* fixed infoframe configuration not linked to the mode */
260 infoframe.colorspace = HDMI_COLORSPACE_RGB;
261 infoframe.quantization_range = HDMI_QUANTIZATION_RANGE_DEFAULT;
262 infoframe.colorimetry = HDMI_COLORIMETRY_NONE;
263
264 ret = hdmi_avi_infoframe_pack(&infoframe, buffer, sizeof(buffer));
265 if (ret < 0) {
266 DRM_ERROR("failed to pack AVI infoframe: %d\n", ret);
267 return ret;
268 }
269
270 /* Disable transmission slot for AVI infoframe */
271 val = hdmi_read(hdmi, HDMI_SW_DI_CFG);
272 val &= ~HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, HDMI_IFRAME_SLOT_AVI);
273 hdmi_write(hdmi, val, HDMI_SW_DI_CFG);
274
275 /* Infoframe header */
276 val = buffer[0x0];
277 val |= buffer[0x1] << 8;
278 val |= buffer[0x2] << 16;
279 hdmi_write(hdmi, val, HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_AVI));
280
281 /* Infoframe packet bytes */
282 val = frame[0x0];
283 val |= frame[0x1] << 8;
284 val |= frame[0x2] << 16;
285 val |= frame[0x3] << 24;
286 hdmi_write(hdmi, val, HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_AVI));
287
288 val = frame[0x4];
289 val |= frame[0x5] << 8;
290 val |= frame[0x6] << 16;
291 val |= frame[0x7] << 24;
292 hdmi_write(hdmi, val, HDMI_SW_DI_N_PKT_WORD1(HDMI_IFRAME_SLOT_AVI));
293
294 val = frame[0x8];
295 val |= frame[0x9] << 8;
296 val |= frame[0xA] << 16;
297 val |= frame[0xB] << 24;
298 hdmi_write(hdmi, val, HDMI_SW_DI_N_PKT_WORD2(HDMI_IFRAME_SLOT_AVI));
299
300 val = frame[0xC];
301 val |= frame[0xD] << 8;
302 hdmi_write(hdmi, val, HDMI_SW_DI_N_PKT_WORD3(HDMI_IFRAME_SLOT_AVI));
303
304 /* Enable transmission slot for AVI infoframe
305 * According to the hdmi specification, AVI infoframe should be
306 * transmitted at least once per two video fields
307 */
308 val = hdmi_read(hdmi, HDMI_SW_DI_CFG);
309 val |= HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_FIELD, HDMI_IFRAME_SLOT_AVI);
310 hdmi_write(hdmi, val, HDMI_SW_DI_CFG);
311
312 return 0;
313}
314
315/**
316 * Software reset of the hdmi subsystem
317 *
318 * @hdmi: pointer on the hdmi internal structure
319 *
320 */
321#define HDMI_TIMEOUT_SWRESET 100 /*milliseconds */
322static void hdmi_swreset(struct sti_hdmi *hdmi)
323{
324 u32 val;
325
326 DRM_DEBUG_DRIVER("\n");
327
328 /* Enable hdmi_audio clock only during hdmi reset */
329 if (clk_prepare_enable(hdmi->clk_audio))
330 DRM_INFO("Failed to prepare/enable hdmi_audio clk\n");
331
332 /* Sw reset */
333 hdmi->event_received = false;
334
335 val = hdmi_read(hdmi, HDMI_CFG);
336 val |= HDMI_CFG_SW_RST_EN;
337 hdmi_write(hdmi, val, HDMI_CFG);
338
339 /* Wait reset completed */
340 wait_event_interruptible_timeout(hdmi->wait_event,
341 hdmi->event_received == true,
342 msecs_to_jiffies
343 (HDMI_TIMEOUT_SWRESET));
344
345 /*
346 * HDMI_STA_SW_RST bit is set to '1' when SW_RST bit in HDMI_CFG is
347 * set to '1' and clk_audio is running.
348 */
349 if ((hdmi_read(hdmi, HDMI_STA) & HDMI_STA_SW_RST) == 0)
350 DRM_DEBUG_DRIVER("Warning: HDMI sw reset timeout occurs\n");
351
352 val = hdmi_read(hdmi, HDMI_CFG);
353 val &= ~HDMI_CFG_SW_RST_EN;
354 hdmi_write(hdmi, val, HDMI_CFG);
355
356 /* Disable hdmi_audio clock. Not used anymore for drm purpose */
357 clk_disable_unprepare(hdmi->clk_audio);
358}
359
360static void sti_hdmi_disable(struct drm_bridge *bridge)
361{
362 struct sti_hdmi *hdmi = bridge->driver_private;
363
364 u32 val = hdmi_read(hdmi, HDMI_CFG);
365
366 if (!hdmi->enabled)
367 return;
368
369 DRM_DEBUG_DRIVER("\n");
370
371 /* Disable HDMI */
372 val &= ~HDMI_CFG_DEVICE_EN;
373 hdmi_write(hdmi, val, HDMI_CFG);
374
375 hdmi_write(hdmi, 0xffffffff, HDMI_INT_CLR);
376
377 /* Stop the phy */
378 hdmi->phy_ops->stop(hdmi);
379
380 /* Set the default channel data to be a dark red */
381 hdmi_write(hdmi, 0x0000, HDMI_DFLT_CHL0_DAT);
382 hdmi_write(hdmi, 0x0000, HDMI_DFLT_CHL1_DAT);
383 hdmi_write(hdmi, 0x0060, HDMI_DFLT_CHL2_DAT);
384
385 /* Disable/unprepare hdmi clock */
386 clk_disable_unprepare(hdmi->clk_phy);
387 clk_disable_unprepare(hdmi->clk_tmds);
388 clk_disable_unprepare(hdmi->clk_pix);
389
390 hdmi->enabled = false;
391}
392
393static void sti_hdmi_pre_enable(struct drm_bridge *bridge)
394{
395 struct sti_hdmi *hdmi = bridge->driver_private;
396
397 DRM_DEBUG_DRIVER("\n");
398
399 if (hdmi->enabled)
400 return;
401
402 /* Prepare/enable clocks */
403 if (clk_prepare_enable(hdmi->clk_pix))
404 DRM_ERROR("Failed to prepare/enable hdmi_pix clk\n");
405 if (clk_prepare_enable(hdmi->clk_tmds))
406 DRM_ERROR("Failed to prepare/enable hdmi_tmds clk\n");
407 if (clk_prepare_enable(hdmi->clk_phy))
408 DRM_ERROR("Failed to prepare/enable hdmi_rejec_pll clk\n");
409
410 hdmi->enabled = true;
411
412 /* Program hdmi serializer and start phy */
413 if (!hdmi->phy_ops->start(hdmi)) {
414 DRM_ERROR("Unable to start hdmi phy\n");
415 return;
416 }
417
418 /* Program hdmi active area */
419 hdmi_active_area(hdmi);
420
421 /* Enable working interrupts */
422 hdmi_write(hdmi, HDMI_WORKING_INT, HDMI_INT_EN);
423
424 /* Program hdmi config */
425 hdmi_config(hdmi);
426
427 /* Program AVI infoframe */
428 if (hdmi_avi_infoframe_config(hdmi))
429 DRM_ERROR("Unable to configure AVI infoframe\n");
430
431 /* Sw reset */
432 hdmi_swreset(hdmi);
433}
434
435static void sti_hdmi_set_mode(struct drm_bridge *bridge,
436 struct drm_display_mode *mode,
437 struct drm_display_mode *adjusted_mode)
438{
439 struct sti_hdmi *hdmi = bridge->driver_private;
440 int ret;
441
442 DRM_DEBUG_DRIVER("\n");
443
444 /* Copy the drm display mode in the connector local structure */
445 memcpy(&hdmi->mode, mode, sizeof(struct drm_display_mode));
446
447 /* Update clock framerate according to the selected mode */
448 ret = clk_set_rate(hdmi->clk_pix, mode->clock * 1000);
449 if (ret < 0) {
450 DRM_ERROR("Cannot set rate (%dHz) for hdmi_pix clk\n",
451 mode->clock * 1000);
452 return;
453 }
454 ret = clk_set_rate(hdmi->clk_phy, mode->clock * 1000);
455 if (ret < 0) {
456 DRM_ERROR("Cannot set rate (%dHz) for hdmi_rejection_pll clk\n",
457 mode->clock * 1000);
458 return;
459 }
460}
461
462static void sti_hdmi_bridge_nope(struct drm_bridge *bridge)
463{
464 /* do nothing */
465}
466
467static void sti_hdmi_brigde_destroy(struct drm_bridge *bridge)
468{
469 drm_bridge_cleanup(bridge);
470 kfree(bridge);
471}
472
473static const struct drm_bridge_funcs sti_hdmi_bridge_funcs = {
474 .pre_enable = sti_hdmi_pre_enable,
475 .enable = sti_hdmi_bridge_nope,
476 .disable = sti_hdmi_disable,
477 .post_disable = sti_hdmi_bridge_nope,
478 .mode_set = sti_hdmi_set_mode,
479 .destroy = sti_hdmi_brigde_destroy,
480};
481
482static int sti_hdmi_connector_get_modes(struct drm_connector *connector)
483{
484 struct i2c_adapter *i2c_adap;
485 struct edid *edid;
486 int count;
487
488 DRM_DEBUG_DRIVER("\n");
489
490 i2c_adap = i2c_get_adapter(1);
491 if (!i2c_adap)
492 goto fail;
493
494 edid = drm_get_edid(connector, i2c_adap);
495 if (!edid)
496 goto fail;
497
498 count = drm_add_edid_modes(connector, edid);
499 drm_mode_connector_update_edid_property(connector, edid);
500
501 kfree(edid);
502 return count;
503
504fail:
505 DRM_ERROR("Can not read HDMI EDID\n");
506 return 0;
507}
508
509#define CLK_TOLERANCE_HZ 50
510
511static int sti_hdmi_connector_mode_valid(struct drm_connector *connector,
512 struct drm_display_mode *mode)
513{
514 int target = mode->clock * 1000;
515 int target_min = target - CLK_TOLERANCE_HZ;
516 int target_max = target + CLK_TOLERANCE_HZ;
517 int result;
518 struct sti_hdmi_connector *hdmi_connector
519 = to_sti_hdmi_connector(connector);
520 struct sti_hdmi *hdmi = hdmi_connector->hdmi;
521
522
523 result = clk_round_rate(hdmi->clk_pix, target);
524
525 DRM_DEBUG_DRIVER("target rate = %d => available rate = %d\n",
526 target, result);
527
528 if ((result < target_min) || (result > target_max)) {
529 DRM_DEBUG_DRIVER("hdmi pixclk=%d not supported\n", target);
530 return MODE_BAD;
531 }
532
533 return MODE_OK;
534}
535
536struct drm_encoder *sti_hdmi_best_encoder(struct drm_connector *connector)
537{
538 struct sti_hdmi_connector *hdmi_connector
539 = to_sti_hdmi_connector(connector);
540
541 /* Best encoder is the one associated during connector creation */
542 return hdmi_connector->encoder;
543}
544
545static struct drm_connector_helper_funcs sti_hdmi_connector_helper_funcs = {
546 .get_modes = sti_hdmi_connector_get_modes,
547 .mode_valid = sti_hdmi_connector_mode_valid,
548 .best_encoder = sti_hdmi_best_encoder,
549};
550
551/* get detection status of display device */
552static enum drm_connector_status
553sti_hdmi_connector_detect(struct drm_connector *connector, bool force)
554{
555 struct sti_hdmi_connector *hdmi_connector
556 = to_sti_hdmi_connector(connector);
557 struct sti_hdmi *hdmi = hdmi_connector->hdmi;
558
559 DRM_DEBUG_DRIVER("\n");
560
561 if (hdmi->hpd) {
562 DRM_DEBUG_DRIVER("hdmi cable connected\n");
563 return connector_status_connected;
564 }
565
566 DRM_DEBUG_DRIVER("hdmi cable disconnected\n");
567 return connector_status_disconnected;
568}
569
570static void sti_hdmi_connector_destroy(struct drm_connector *connector)
571{
572 struct sti_hdmi_connector *hdmi_connector
573 = to_sti_hdmi_connector(connector);
574
575 drm_connector_unregister(connector);
576 drm_connector_cleanup(connector);
577 kfree(hdmi_connector);
578}
579
580static struct drm_connector_funcs sti_hdmi_connector_funcs = {
581 .dpms = drm_helper_connector_dpms,
582 .fill_modes = drm_helper_probe_single_connector_modes,
583 .detect = sti_hdmi_connector_detect,
584 .destroy = sti_hdmi_connector_destroy,
585};
586
587static struct drm_encoder *sti_hdmi_find_encoder(struct drm_device *dev)
588{
589 struct drm_encoder *encoder;
590
591 list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
592 if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS)
593 return encoder;
594 }
595
596 return NULL;
597}
598
599static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
600{
601 struct sti_hdmi *hdmi = dev_get_drvdata(dev);
602 struct drm_device *drm_dev = data;
603 struct drm_encoder *encoder;
604 struct sti_hdmi_connector *connector;
605 struct drm_connector *drm_connector;
606 struct drm_bridge *bridge;
607 struct i2c_adapter *i2c_adap;
608 int err;
609
610 i2c_adap = i2c_get_adapter(1);
611 if (!i2c_adap)
612 return -EPROBE_DEFER;
613
614 /* Set the drm device handle */
615 hdmi->drm_dev = drm_dev;
616
617 encoder = sti_hdmi_find_encoder(drm_dev);
618 if (!encoder)
619 return -ENOMEM;
620
621 connector = devm_kzalloc(dev, sizeof(*connector), GFP_KERNEL);
622 if (!connector)
623 return -ENOMEM;
624
625 connector->hdmi = hdmi;
626
627 bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL);
628 if (!bridge)
629 return -ENOMEM;
630
631 bridge->driver_private = hdmi;
632 drm_bridge_init(drm_dev, bridge, &sti_hdmi_bridge_funcs);
633
634 encoder->bridge = bridge;
635 connector->encoder = encoder;
636
637 drm_connector = (struct drm_connector *)connector;
638
639 drm_connector->polled = DRM_CONNECTOR_POLL_HPD;
640
641 drm_connector_init(drm_dev, drm_connector,
642 &sti_hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA);
643 drm_connector_helper_add(drm_connector,
644 &sti_hdmi_connector_helper_funcs);
645
646 err = drm_connector_register(drm_connector);
647 if (err)
648 goto err_connector;
649
650 err = drm_mode_connector_attach_encoder(drm_connector, encoder);
651 if (err) {
652 DRM_ERROR("Failed to attach a connector to a encoder\n");
653 goto err_sysfs;
654 }
655
656 /* Enable default interrupts */
657 hdmi_write(hdmi, HDMI_DEFAULT_INT, HDMI_INT_EN);
658
659 return 0;
660
661err_sysfs:
662 drm_connector_unregister(drm_connector);
663err_connector:
664 drm_bridge_cleanup(bridge);
665 drm_connector_cleanup(drm_connector);
666 return -EINVAL;
667}
668
669static void sti_hdmi_unbind(struct device *dev,
670 struct device *master, void *data)
671{
672 /* do nothing */
673}
674
675static const struct component_ops sti_hdmi_ops = {
676 .bind = sti_hdmi_bind,
677 .unbind = sti_hdmi_unbind,
678};
679
680static struct of_device_id hdmi_of_match[] = {
681 {
682 .compatible = "st,stih416-hdmi",
683 .data = &tx3g0c55phy_ops,
684 }, {
685 .compatible = "st,stih407-hdmi",
686 .data = &tx3g4c28phy_ops,
687 }, {
688 /* end node */
689 }
690};
691MODULE_DEVICE_TABLE(of, hdmi_of_match);
692
693static int sti_hdmi_probe(struct platform_device *pdev)
694{
695 struct device *dev = &pdev->dev;
696 struct sti_hdmi *hdmi;
697 struct device_node *np = dev->of_node;
698 struct resource *res;
699 int ret;
700
701 DRM_INFO("%s\n", __func__);
702
703 hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
704 if (!hdmi)
705 return -ENOMEM;
706
707 hdmi->dev = pdev->dev;
708
709 /* Get resources */
710 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hdmi-reg");
711 if (!res) {
712 DRM_ERROR("Invalid hdmi resource\n");
713 return -ENOMEM;
714 }
715 hdmi->regs = devm_ioremap_nocache(dev, res->start, resource_size(res));
716 if (IS_ERR(hdmi->regs))
717 return PTR_ERR(hdmi->regs);
718
719 if (of_device_is_compatible(np, "st,stih416-hdmi")) {
720 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
721 "syscfg");
722 if (!res) {
723 DRM_ERROR("Invalid syscfg resource\n");
724 return -ENOMEM;
725 }
726 hdmi->syscfg = devm_ioremap_nocache(dev, res->start,
727 resource_size(res));
728 if (IS_ERR(hdmi->syscfg))
729 return PTR_ERR(hdmi->syscfg);
730
731 }
732
733 hdmi->phy_ops = (struct hdmi_phy_ops *)
734 of_match_node(hdmi_of_match, np)->data;
735
736 /* Get clock resources */
737 hdmi->clk_pix = devm_clk_get(dev, "pix");
738 if (IS_ERR(hdmi->clk_pix)) {
739 DRM_ERROR("Cannot get hdmi_pix clock\n");
740 return PTR_ERR(hdmi->clk_pix);
741 }
742
743 hdmi->clk_tmds = devm_clk_get(dev, "tmds");
744 if (IS_ERR(hdmi->clk_tmds)) {
745 DRM_ERROR("Cannot get hdmi_tmds clock\n");
746 return PTR_ERR(hdmi->clk_tmds);
747 }
748
749 hdmi->clk_phy = devm_clk_get(dev, "phy");
750 if (IS_ERR(hdmi->clk_phy)) {
751 DRM_ERROR("Cannot get hdmi_phy clock\n");
752 return PTR_ERR(hdmi->clk_phy);
753 }
754
755 hdmi->clk_audio = devm_clk_get(dev, "audio");
756 if (IS_ERR(hdmi->clk_audio)) {
757 DRM_ERROR("Cannot get hdmi_audio clock\n");
758 return PTR_ERR(hdmi->clk_audio);
759 }
760
761 hdmi->hpd_gpio = of_get_named_gpio(np, "hdmi,hpd-gpio", 0);
762 if (hdmi->hpd_gpio < 0) {
763 DRM_ERROR("Failed to get hdmi hpd-gpio\n");
764 return -EIO;
765 }
766
767 hdmi->hpd = gpio_get_value(hdmi->hpd_gpio);
768
769 init_waitqueue_head(&hdmi->wait_event);
770
771 hdmi->irq = platform_get_irq_byname(pdev, "irq");
772
773 ret = devm_request_threaded_irq(dev, hdmi->irq, hdmi_irq,
774 hdmi_irq_thread, IRQF_ONESHOT, dev_name(dev), hdmi);
775 if (ret) {
776 DRM_ERROR("Failed to register HDMI interrupt\n");
777 return ret;
778 }
779
780 hdmi->reset = devm_reset_control_get(dev, "hdmi");
781 /* Take hdmi out of reset */
782 if (!IS_ERR(hdmi->reset))
783 reset_control_deassert(hdmi->reset);
784
785 platform_set_drvdata(pdev, hdmi);
786
787 return component_add(&pdev->dev, &sti_hdmi_ops);
788}
789
790static int sti_hdmi_remove(struct platform_device *pdev)
791{
792 component_del(&pdev->dev, &sti_hdmi_ops);
793 return 0;
794}
795
796struct platform_driver sti_hdmi_driver = {
797 .driver = {
798 .name = "sti-hdmi",
799 .owner = THIS_MODULE,
800 .of_match_table = hdmi_of_match,
801 },
802 .probe = sti_hdmi_probe,
803 .remove = sti_hdmi_remove,
804};
805
806module_platform_driver(sti_hdmi_driver);
807
808MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
809MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
810MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/sti/sti_hdmi.h b/drivers/gpu/drm/sti/sti_hdmi.h
new file mode 100644
index 000000000000..61bec6557ceb
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_hdmi.h
@@ -0,0 +1,88 @@
1/*
2 * Copyright (C) STMicroelectronics SA 2014
3 * Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
5 */
6
7#ifndef _STI_HDMI_H_
8#define _STI_HDMI_H_
9
10#include <linux/platform_device.h>
11
12#include <drm/drmP.h>
13
14#define HDMI_STA 0x0010
15#define HDMI_STA_DLL_LCK BIT(5)
16
17struct sti_hdmi;
18
19struct hdmi_phy_ops {
20 bool (*start)(struct sti_hdmi *hdmi);
21 void (*stop)(struct sti_hdmi *hdmi);
22};
23
24/**
25 * STI hdmi structure
26 *
27 * @dev: driver device
28 * @drm_dev: pointer to drm device
29 * @mode: current display mode selected
30 * @regs: hdmi register
31 * @syscfg: syscfg register for pll rejection configuration
32 * @clk_pix: hdmi pixel clock
33 * @clk_tmds: hdmi tmds clock
34 * @clk_phy: hdmi phy clock
35 * @clk_audio: hdmi audio clock
36 * @irq: hdmi interrupt number
37 * @irq_status: interrupt status register
38 * @phy_ops: phy start/stop operations
39 * @enabled: true if hdmi is enabled else false
40 * @hpd_gpio: hdmi hot plug detect gpio number
41 * @hpd: hot plug detect status
42 * @wait_event: wait event
43 * @event_received: wait event status
44 * @reset: reset control of the hdmi phy
45 */
46struct sti_hdmi {
47 struct device dev;
48 struct drm_device *drm_dev;
49 struct drm_display_mode mode;
50 void __iomem *regs;
51 void __iomem *syscfg;
52 struct clk *clk_pix;
53 struct clk *clk_tmds;
54 struct clk *clk_phy;
55 struct clk *clk_audio;
56 int irq;
57 u32 irq_status;
58 struct hdmi_phy_ops *phy_ops;
59 bool enabled;
60 int hpd_gpio;
61 bool hpd;
62 wait_queue_head_t wait_event;
63 bool event_received;
64 struct reset_control *reset;
65};
66
67u32 hdmi_read(struct sti_hdmi *hdmi, int offset);
68void hdmi_write(struct sti_hdmi *hdmi, u32 val, int offset);
69
70/**
71 * hdmi phy config structure
72 *
73 * A pointer to an array of these structures is passed to a TMDS (HDMI) output
74 * via the control interface to provide board and SoC specific
75 * configurations of the HDMI PHY. Each entry in the array specifies a hardware
76 * specific configuration for a given TMDS clock frequency range.
77 *
78 * @min_tmds_freq: Lower bound of TMDS clock frequency this entry applies to
79 * @max_tmds_freq: Upper bound of TMDS clock frequency this entry applies to
80 * @config: SoC specific register configuration
81 */
82struct hdmi_phy_config {
83 u32 min_tmds_freq;
84 u32 max_tmds_freq;
85 u32 config[4];
86};
87
88#endif
diff --git a/drivers/gpu/drm/sti/sti_hdmi_tx3g0c55phy.c b/drivers/gpu/drm/sti/sti_hdmi_tx3g0c55phy.c
new file mode 100644
index 000000000000..49ae8e44b285
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_hdmi_tx3g0c55phy.c
@@ -0,0 +1,336 @@
1/*
2 * Copyright (C) STMicroelectronics SA 2014
3 * Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
5 */
6
7#include "sti_hdmi_tx3g0c55phy.h"
8
9#define HDMI_SRZ_PLL_CFG 0x0504
10#define HDMI_SRZ_TAP_1 0x0508
11#define HDMI_SRZ_TAP_2 0x050C
12#define HDMI_SRZ_TAP_3 0x0510
13#define HDMI_SRZ_CTRL 0x0514
14
15#define HDMI_SRZ_PLL_CFG_POWER_DOWN BIT(0)
16#define HDMI_SRZ_PLL_CFG_VCOR_SHIFT 1
17#define HDMI_SRZ_PLL_CFG_VCOR_425MHZ 0
18#define HDMI_SRZ_PLL_CFG_VCOR_850MHZ 1
19#define HDMI_SRZ_PLL_CFG_VCOR_1700MHZ 2
20#define HDMI_SRZ_PLL_CFG_VCOR_3000MHZ 3
21#define HDMI_SRZ_PLL_CFG_VCOR_MASK 3
22#define HDMI_SRZ_PLL_CFG_VCOR(x) (x << HDMI_SRZ_PLL_CFG_VCOR_SHIFT)
23#define HDMI_SRZ_PLL_CFG_NDIV_SHIFT 8
24#define HDMI_SRZ_PLL_CFG_NDIV_MASK (0x1F << HDMI_SRZ_PLL_CFG_NDIV_SHIFT)
25#define HDMI_SRZ_PLL_CFG_MODE_SHIFT 16
26#define HDMI_SRZ_PLL_CFG_MODE_13_5_MHZ 0x1
27#define HDMI_SRZ_PLL_CFG_MODE_25_2_MHZ 0x4
28#define HDMI_SRZ_PLL_CFG_MODE_27_MHZ 0x5
29#define HDMI_SRZ_PLL_CFG_MODE_33_75_MHZ 0x6
30#define HDMI_SRZ_PLL_CFG_MODE_40_5_MHZ 0x7
31#define HDMI_SRZ_PLL_CFG_MODE_54_MHZ 0x8
32#define HDMI_SRZ_PLL_CFG_MODE_67_5_MHZ 0x9
33#define HDMI_SRZ_PLL_CFG_MODE_74_25_MHZ 0xA
34#define HDMI_SRZ_PLL_CFG_MODE_81_MHZ 0xB
35#define HDMI_SRZ_PLL_CFG_MODE_82_5_MHZ 0xC
36#define HDMI_SRZ_PLL_CFG_MODE_108_MHZ 0xD
37#define HDMI_SRZ_PLL_CFG_MODE_148_5_MHZ 0xE
38#define HDMI_SRZ_PLL_CFG_MODE_165_MHZ 0xF
39#define HDMI_SRZ_PLL_CFG_MODE_MASK 0xF
40#define HDMI_SRZ_PLL_CFG_MODE(x) (x << HDMI_SRZ_PLL_CFG_MODE_SHIFT)
41
42#define HDMI_SRZ_CTRL_POWER_DOWN (1 << 0)
43#define HDMI_SRZ_CTRL_EXTERNAL_DATA_EN (1 << 1)
44
45/* sysconf registers */
46#define HDMI_REJECTION_PLL_CONFIGURATION 0x0858 /* SYSTEM_CONFIG2534 */
47#define HDMI_REJECTION_PLL_STATUS 0x0948 /* SYSTEM_CONFIG2594 */
48
49#define REJECTION_PLL_HDMI_ENABLE_SHIFT 0
50#define REJECTION_PLL_HDMI_ENABLE_MASK (0x1 << REJECTION_PLL_HDMI_ENABLE_SHIFT)
51#define REJECTION_PLL_HDMI_PDIV_SHIFT 24
52#define REJECTION_PLL_HDMI_PDIV_MASK (0x7 << REJECTION_PLL_HDMI_PDIV_SHIFT)
53#define REJECTION_PLL_HDMI_NDIV_SHIFT 16
54#define REJECTION_PLL_HDMI_NDIV_MASK (0xFF << REJECTION_PLL_HDMI_NDIV_SHIFT)
55#define REJECTION_PLL_HDMI_MDIV_SHIFT 8
56#define REJECTION_PLL_HDMI_MDIV_MASK (0xFF << REJECTION_PLL_HDMI_MDIV_SHIFT)
57
58#define REJECTION_PLL_HDMI_REJ_PLL_LOCK BIT(0)
59
60#define HDMI_TIMEOUT_PLL_LOCK 50 /*milliseconds */
61
62/**
63 * pll mode structure
64 *
65 * A pointer to an array of these structures is passed to a TMDS (HDMI) output
66 * via the control interface to provide board and SoC specific
67 * configurations of the HDMI PHY. Each entry in the array specifies a hardware
68 * specific configuration for a given TMDS clock frequency range. The array
69 * should be terminated with an entry that has all fields set to zero.
70 *
71 * @min: Lower bound of TMDS clock frequency this entry applies to
72 * @max: Upper bound of TMDS clock frequency this entry applies to
73 * @mode: SoC specific register configuration
74 */
75struct pllmode {
76 u32 min;
77 u32 max;
78 u32 mode;
79};
80
81#define NB_PLL_MODE 7
82static struct pllmode pllmodes[NB_PLL_MODE] = {
83 {13500000, 13513500, HDMI_SRZ_PLL_CFG_MODE_13_5_MHZ},
84 {25174800, 25200000, HDMI_SRZ_PLL_CFG_MODE_25_2_MHZ},
85 {27000000, 27027000, HDMI_SRZ_PLL_CFG_MODE_27_MHZ},
86 {54000000, 54054000, HDMI_SRZ_PLL_CFG_MODE_54_MHZ},
87 {72000000, 74250000, HDMI_SRZ_PLL_CFG_MODE_74_25_MHZ},
88 {108000000, 108108000, HDMI_SRZ_PLL_CFG_MODE_108_MHZ},
89 {148351648, 297000000, HDMI_SRZ_PLL_CFG_MODE_148_5_MHZ}
90};
91
92#define NB_HDMI_PHY_CONFIG 5
93static struct hdmi_phy_config hdmiphy_config[NB_HDMI_PHY_CONFIG] = {
94 {0, 40000000, {0x00101010, 0x00101010, 0x00101010, 0x02} },
95 {40000000, 140000000, {0x00111111, 0x00111111, 0x00111111, 0x02} },
96 {140000000, 160000000, {0x00131313, 0x00101010, 0x00101010, 0x02} },
97 {160000000, 250000000, {0x00131313, 0x00111111, 0x00111111, 0x03FE} },
98 {250000000, 300000000, {0x00151515, 0x00101010, 0x00101010, 0x03FE} },
99};
100
101#define PLL_CHANGE_DELAY 1 /* ms */
102
103/**
104 * Disable the pll rejection
105 *
106 * @hdmi: pointer on the hdmi internal structure
107 *
108 * return true if the pll has been disabled
109 */
110static bool disable_pll_rejection(struct sti_hdmi *hdmi)
111{
112 u32 val;
113
114 DRM_DEBUG_DRIVER("\n");
115
116 val = readl(hdmi->syscfg + HDMI_REJECTION_PLL_CONFIGURATION);
117 val &= ~REJECTION_PLL_HDMI_ENABLE_MASK;
118 writel(val, hdmi->syscfg + HDMI_REJECTION_PLL_CONFIGURATION);
119
120 msleep(PLL_CHANGE_DELAY);
121 val = readl(hdmi->syscfg + HDMI_REJECTION_PLL_STATUS);
122
123 return !(val & REJECTION_PLL_HDMI_REJ_PLL_LOCK);
124}
125
126/**
127 * Enable the old BCH/rejection PLL is now reused to provide the CLKPXPLL
128 * clock input to the new PHY PLL that generates the serializer clock
129 * (TMDS*10) and the TMDS clock which is now fed back into the HDMI
130 * formatter instead of the TMDS clock line from ClockGenB.
131 *
132 * @hdmi: pointer on the hdmi internal structure
133 *
134 * return true if pll has been correctly set
135 */
136static bool enable_pll_rejection(struct sti_hdmi *hdmi)
137{
138 unsigned int inputclock;
139 u32 mdiv, ndiv, pdiv, val;
140
141 DRM_DEBUG_DRIVER("\n");
142
143 if (!disable_pll_rejection(hdmi))
144 return false;
145
146 inputclock = hdmi->mode.clock * 1000;
147
148 DRM_DEBUG_DRIVER("hdmi rejection pll input clock = %dHz\n", inputclock);
149
150
151 /* Power up the HDMI rejection PLL
152 * Note: On this SoC (stiH416) we are forced to have the input clock
153 * be equal to the HDMI pixel clock.
154 *
155 * The values here have been suggested by validation however they are
156 * still provisional and subject to change.
157 *
158 * PLLout = (Fin*Mdiv) / ((2 * Ndiv) / 2^Pdiv)
159 */
160 if (inputclock < 50000000) {
161 /*
162 * For slower clocks we need to multiply more to keep the
163 * internal VCO frequency within the physical specification
164 * of the PLL.
165 */
166 pdiv = 4;
167 ndiv = 240;
168 mdiv = 30;
169 } else {
170 pdiv = 2;
171 ndiv = 60;
172 mdiv = 30;
173 }
174
175 val = readl(hdmi->syscfg + HDMI_REJECTION_PLL_CONFIGURATION);
176
177 val &= ~(REJECTION_PLL_HDMI_PDIV_MASK |
178 REJECTION_PLL_HDMI_NDIV_MASK |
179 REJECTION_PLL_HDMI_MDIV_MASK |
180 REJECTION_PLL_HDMI_ENABLE_MASK);
181
182 val |= (pdiv << REJECTION_PLL_HDMI_PDIV_SHIFT) |
183 (ndiv << REJECTION_PLL_HDMI_NDIV_SHIFT) |
184 (mdiv << REJECTION_PLL_HDMI_MDIV_SHIFT) |
185 (0x1 << REJECTION_PLL_HDMI_ENABLE_SHIFT);
186
187 writel(val, hdmi->syscfg + HDMI_REJECTION_PLL_CONFIGURATION);
188
189 msleep(PLL_CHANGE_DELAY);
190 val = readl(hdmi->syscfg + HDMI_REJECTION_PLL_STATUS);
191
192 return (val & REJECTION_PLL_HDMI_REJ_PLL_LOCK);
193}
194
195/**
196 * Start hdmi phy macro cell tx3g0c55
197 *
198 * @hdmi: pointer on the hdmi internal structure
199 *
200 * Return false if an error occur
201 */
202static bool sti_hdmi_tx3g0c55phy_start(struct sti_hdmi *hdmi)
203{
204 u32 ckpxpll = hdmi->mode.clock * 1000;
205 u32 val, tmdsck, freqvco, pllctrl = 0;
206 unsigned int i;
207
208 if (!enable_pll_rejection(hdmi))
209 return false;
210
211 DRM_DEBUG_DRIVER("ckpxpll = %dHz\n", ckpxpll);
212
213 /* Assuming no pixel repetition and 24bits color */
214 tmdsck = ckpxpll;
215 pllctrl = 2 << HDMI_SRZ_PLL_CFG_NDIV_SHIFT;
216
217 /*
218 * Setup the PLL mode parameter based on the ckpxpll. If we haven't got
219 * a clock frequency supported by one of the specific PLL modes then we
220 * will end up using the generic mode (0) which only supports a 10x
221 * multiplier, hence only 24bit color.
222 */
223 for (i = 0; i < NB_PLL_MODE; i++) {
224 if (ckpxpll >= pllmodes[i].min && ckpxpll <= pllmodes[i].max)
225 pllctrl |= HDMI_SRZ_PLL_CFG_MODE(pllmodes[i].mode);
226 }
227
228 freqvco = tmdsck * 10;
229 if (freqvco <= 425000000UL)
230 pllctrl |= HDMI_SRZ_PLL_CFG_VCOR(HDMI_SRZ_PLL_CFG_VCOR_425MHZ);
231 else if (freqvco <= 850000000UL)
232 pllctrl |= HDMI_SRZ_PLL_CFG_VCOR(HDMI_SRZ_PLL_CFG_VCOR_850MHZ);
233 else if (freqvco <= 1700000000UL)
234 pllctrl |= HDMI_SRZ_PLL_CFG_VCOR(HDMI_SRZ_PLL_CFG_VCOR_1700MHZ);
235 else if (freqvco <= 2970000000UL)
236 pllctrl |= HDMI_SRZ_PLL_CFG_VCOR(HDMI_SRZ_PLL_CFG_VCOR_3000MHZ);
237 else {
238 DRM_ERROR("PHY serializer clock out of range\n");
239 goto err;
240 }
241
242 /*
243 * Configure and power up the PHY PLL
244 */
245 hdmi->event_received = false;
246 DRM_DEBUG_DRIVER("pllctrl = 0x%x\n", pllctrl);
247 hdmi_write(hdmi, pllctrl, HDMI_SRZ_PLL_CFG);
248
249 /* wait PLL interrupt */
250 wait_event_interruptible_timeout(hdmi->wait_event,
251 hdmi->event_received == true,
252 msecs_to_jiffies
253 (HDMI_TIMEOUT_PLL_LOCK));
254
255 if ((hdmi_read(hdmi, HDMI_STA) & HDMI_STA_DLL_LCK) == 0) {
256 DRM_ERROR("hdmi phy pll not locked\n");
257 goto err;
258 }
259
260 DRM_DEBUG_DRIVER("got PHY PLL Lock\n");
261
262 /*
263 * To configure the source termination and pre-emphasis appropriately
264 * for different high speed TMDS clock frequencies a phy configuration
265 * table must be provided, tailored to the SoC and board combination.
266 */
267 for (i = 0; i < NB_HDMI_PHY_CONFIG; i++) {
268 if ((hdmiphy_config[i].min_tmds_freq <= tmdsck) &&
269 (hdmiphy_config[i].max_tmds_freq >= tmdsck)) {
270 val = hdmiphy_config[i].config[0];
271 hdmi_write(hdmi, val, HDMI_SRZ_TAP_1);
272 val = hdmiphy_config[i].config[1];
273 hdmi_write(hdmi, val, HDMI_SRZ_TAP_2);
274 val = hdmiphy_config[i].config[2];
275 hdmi_write(hdmi, val, HDMI_SRZ_TAP_3);
276 val = hdmiphy_config[i].config[3];
277 val |= HDMI_SRZ_CTRL_EXTERNAL_DATA_EN;
278 val &= ~HDMI_SRZ_CTRL_POWER_DOWN;
279 hdmi_write(hdmi, val, HDMI_SRZ_CTRL);
280
281 DRM_DEBUG_DRIVER("serializer cfg 0x%x 0x%x 0x%x 0x%x\n",
282 hdmiphy_config[i].config[0],
283 hdmiphy_config[i].config[1],
284 hdmiphy_config[i].config[2],
285 hdmiphy_config[i].config[3]);
286 return true;
287 }
288 }
289
290 /*
291 * Default, power up the serializer with no pre-emphasis or source
292 * termination.
293 */
294 hdmi_write(hdmi, 0x0, HDMI_SRZ_TAP_1);
295 hdmi_write(hdmi, 0x0, HDMI_SRZ_TAP_2);
296 hdmi_write(hdmi, 0x0, HDMI_SRZ_TAP_3);
297 hdmi_write(hdmi, HDMI_SRZ_CTRL_EXTERNAL_DATA_EN, HDMI_SRZ_CTRL);
298
299 return true;
300
301err:
302 disable_pll_rejection(hdmi);
303
304 return false;
305}
306
307/**
308 * Stop hdmi phy macro cell tx3g0c55
309 *
310 * @hdmi: pointer on the hdmi internal structure
311 */
312static void sti_hdmi_tx3g0c55phy_stop(struct sti_hdmi *hdmi)
313{
314 DRM_DEBUG_DRIVER("\n");
315
316 hdmi->event_received = false;
317
318 hdmi_write(hdmi, HDMI_SRZ_CTRL_POWER_DOWN, HDMI_SRZ_CTRL);
319 hdmi_write(hdmi, HDMI_SRZ_PLL_CFG_POWER_DOWN, HDMI_SRZ_PLL_CFG);
320
321 /* wait PLL interrupt */
322 wait_event_interruptible_timeout(hdmi->wait_event,
323 hdmi->event_received == true,
324 msecs_to_jiffies
325 (HDMI_TIMEOUT_PLL_LOCK));
326
327 if (hdmi_read(hdmi, HDMI_STA) & HDMI_STA_DLL_LCK)
328 DRM_ERROR("hdmi phy pll not well disabled\n");
329
330 disable_pll_rejection(hdmi);
331}
332
333struct hdmi_phy_ops tx3g0c55phy_ops = {
334 .start = sti_hdmi_tx3g0c55phy_start,
335 .stop = sti_hdmi_tx3g0c55phy_stop,
336};
diff --git a/drivers/gpu/drm/sti/sti_hdmi_tx3g0c55phy.h b/drivers/gpu/drm/sti/sti_hdmi_tx3g0c55phy.h
new file mode 100644
index 000000000000..068237b3a303
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_hdmi_tx3g0c55phy.h
@@ -0,0 +1,14 @@
1/*
2 * Copyright (C) STMicroelectronics SA 2014
3 * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
5 */
6
7#ifndef _STI_HDMI_TX3G0C55PHY_H_
8#define _STI_HDMI_TX3G0C55PHY_H_
9
10#include "sti_hdmi.h"
11
12extern struct hdmi_phy_ops tx3g0c55phy_ops;
13
14#endif
diff --git a/drivers/gpu/drm/sti/sti_hdmi_tx3g4c28phy.c b/drivers/gpu/drm/sti/sti_hdmi_tx3g4c28phy.c
new file mode 100644
index 000000000000..8e0ceb0ced33
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_hdmi_tx3g4c28phy.c
@@ -0,0 +1,211 @@
1/*
2 * Copyright (C) STMicroelectronics SA 2014
3 * Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
5 */
6
7#include "sti_hdmi_tx3g4c28phy.h"
8
9#define HDMI_SRZ_CFG 0x504
10#define HDMI_SRZ_PLL_CFG 0x510
11#define HDMI_SRZ_ICNTL 0x518
12#define HDMI_SRZ_CALCODE_EXT 0x520
13
14#define HDMI_SRZ_CFG_EN BIT(0)
15#define HDMI_SRZ_CFG_DISABLE_BYPASS_SINK_CURRENT BIT(1)
16#define HDMI_SRZ_CFG_EXTERNAL_DATA BIT(16)
17#define HDMI_SRZ_CFG_RBIAS_EXT BIT(17)
18#define HDMI_SRZ_CFG_EN_SINK_TERM_DETECTION BIT(18)
19#define HDMI_SRZ_CFG_EN_BIASRES_DETECTION BIT(19)
20#define HDMI_SRZ_CFG_EN_SRC_TERMINATION BIT(24)
21
22#define HDMI_SRZ_CFG_INTERNAL_MASK (HDMI_SRZ_CFG_EN | \
23 HDMI_SRZ_CFG_DISABLE_BYPASS_SINK_CURRENT | \
24 HDMI_SRZ_CFG_EXTERNAL_DATA | \
25 HDMI_SRZ_CFG_RBIAS_EXT | \
26 HDMI_SRZ_CFG_EN_SINK_TERM_DETECTION | \
27 HDMI_SRZ_CFG_EN_BIASRES_DETECTION | \
28 HDMI_SRZ_CFG_EN_SRC_TERMINATION)
29
30#define PLL_CFG_EN BIT(0)
31#define PLL_CFG_NDIV_SHIFT (8)
32#define PLL_CFG_IDF_SHIFT (16)
33#define PLL_CFG_ODF_SHIFT (24)
34
35#define ODF_DIV_1 (0)
36#define ODF_DIV_2 (1)
37#define ODF_DIV_4 (2)
38#define ODF_DIV_8 (3)
39
40#define HDMI_TIMEOUT_PLL_LOCK 50 /*milliseconds */
41
42struct plldividers_s {
43 uint32_t min;
44 uint32_t max;
45 uint32_t idf;
46 uint32_t odf;
47};
48
49/*
50 * Functional specification recommended values
51 */
52#define NB_PLL_MODE 5
53static struct plldividers_s plldividers[NB_PLL_MODE] = {
54 {0, 20000000, 1, ODF_DIV_8},
55 {20000000, 42500000, 2, ODF_DIV_8},
56 {42500000, 85000000, 4, ODF_DIV_4},
57 {85000000, 170000000, 8, ODF_DIV_2},
58 {170000000, 340000000, 16, ODF_DIV_1}
59};
60
61#define NB_HDMI_PHY_CONFIG 2
62static struct hdmi_phy_config hdmiphy_config[NB_HDMI_PHY_CONFIG] = {
63 {0, 250000000, {0x0, 0x0, 0x0, 0x0} },
64 {250000000, 300000000, {0x1110, 0x0, 0x0, 0x0} },
65};
66
67/**
68 * Start hdmi phy macro cell tx3g4c28
69 *
70 * @hdmi: pointer on the hdmi internal structure
71 *
72 * Return false if an error occur
73 */
74static bool sti_hdmi_tx3g4c28phy_start(struct sti_hdmi *hdmi)
75{
76 u32 ckpxpll = hdmi->mode.clock * 1000;
77 u32 val, tmdsck, idf, odf, pllctrl = 0;
78 bool foundplldivides = false;
79 int i;
80
81 DRM_DEBUG_DRIVER("ckpxpll = %dHz\n", ckpxpll);
82
83 for (i = 0; i < NB_PLL_MODE; i++) {
84 if (ckpxpll >= plldividers[i].min &&
85 ckpxpll < plldividers[i].max) {
86 idf = plldividers[i].idf;
87 odf = plldividers[i].odf;
88 foundplldivides = true;
89 break;
90 }
91 }
92
93 if (!foundplldivides) {
94 DRM_ERROR("input TMDS clock speed (%d) not supported\n",
95 ckpxpll);
96 goto err;
97 }
98
99 /* Assuming no pixel repetition and 24bits color */
100 tmdsck = ckpxpll;
101 pllctrl |= 40 << PLL_CFG_NDIV_SHIFT;
102
103 if (tmdsck > 340000000) {
104 DRM_ERROR("output TMDS clock (%d) out of range\n", tmdsck);
105 goto err;
106 }
107
108 pllctrl |= idf << PLL_CFG_IDF_SHIFT;
109 pllctrl |= odf << PLL_CFG_ODF_SHIFT;
110
111 /*
112 * Configure and power up the PHY PLL
113 */
114 hdmi->event_received = false;
115 DRM_DEBUG_DRIVER("pllctrl = 0x%x\n", pllctrl);
116 hdmi_write(hdmi, (pllctrl | PLL_CFG_EN), HDMI_SRZ_PLL_CFG);
117
118 /* wait PLL interrupt */
119 wait_event_interruptible_timeout(hdmi->wait_event,
120 hdmi->event_received == true,
121 msecs_to_jiffies
122 (HDMI_TIMEOUT_PLL_LOCK));
123
124 if ((hdmi_read(hdmi, HDMI_STA) & HDMI_STA_DLL_LCK) == 0) {
125 DRM_ERROR("hdmi phy pll not locked\n");
126 goto err;
127 }
128
129 DRM_DEBUG_DRIVER("got PHY PLL Lock\n");
130
131 val = (HDMI_SRZ_CFG_EN |
132 HDMI_SRZ_CFG_EXTERNAL_DATA |
133 HDMI_SRZ_CFG_EN_BIASRES_DETECTION |
134 HDMI_SRZ_CFG_EN_SINK_TERM_DETECTION);
135
136 if (tmdsck > 165000000)
137 val |= HDMI_SRZ_CFG_EN_SRC_TERMINATION;
138
139 /*
140 * To configure the source termination and pre-emphasis appropriately
141 * for different high speed TMDS clock frequencies a phy configuration
142 * table must be provided, tailored to the SoC and board combination.
143 */
144 for (i = 0; i < NB_HDMI_PHY_CONFIG; i++) {
145 if ((hdmiphy_config[i].min_tmds_freq <= tmdsck) &&
146 (hdmiphy_config[i].max_tmds_freq >= tmdsck)) {
147 val |= (hdmiphy_config[i].config[0]
148 & ~HDMI_SRZ_CFG_INTERNAL_MASK);
149 hdmi_write(hdmi, val, HDMI_SRZ_CFG);
150
151 val = hdmiphy_config[i].config[1];
152 hdmi_write(hdmi, val, HDMI_SRZ_ICNTL);
153
154 val = hdmiphy_config[i].config[2];
155 hdmi_write(hdmi, val, HDMI_SRZ_CALCODE_EXT);
156
157 DRM_DEBUG_DRIVER("serializer cfg 0x%x 0x%x 0x%x\n",
158 hdmiphy_config[i].config[0],
159 hdmiphy_config[i].config[1],
160 hdmiphy_config[i].config[2]);
161 return true;
162 }
163 }
164
165 /*
166 * Default, power up the serializer with no pre-emphasis or
167 * output swing correction
168 */
169 hdmi_write(hdmi, val, HDMI_SRZ_CFG);
170 hdmi_write(hdmi, 0x0, HDMI_SRZ_ICNTL);
171 hdmi_write(hdmi, 0x0, HDMI_SRZ_CALCODE_EXT);
172
173 return true;
174
175err:
176 return false;
177}
178
179/**
180 * Stop hdmi phy macro cell tx3g4c28
181 *
182 * @hdmi: pointer on the hdmi internal structure
183 */
184static void sti_hdmi_tx3g4c28phy_stop(struct sti_hdmi *hdmi)
185{
186 int val = 0;
187
188 DRM_DEBUG_DRIVER("\n");
189
190 hdmi->event_received = false;
191
192 val = HDMI_SRZ_CFG_EN_SINK_TERM_DETECTION;
193 val |= HDMI_SRZ_CFG_EN_BIASRES_DETECTION;
194
195 hdmi_write(hdmi, val, HDMI_SRZ_CFG);
196 hdmi_write(hdmi, 0, HDMI_SRZ_PLL_CFG);
197
198 /* wait PLL interrupt */
199 wait_event_interruptible_timeout(hdmi->wait_event,
200 hdmi->event_received == true,
201 msecs_to_jiffies
202 (HDMI_TIMEOUT_PLL_LOCK));
203
204 if (hdmi_read(hdmi, HDMI_STA) & HDMI_STA_DLL_LCK)
205 DRM_ERROR("hdmi phy pll not well disabled\n");
206}
207
208struct hdmi_phy_ops tx3g4c28phy_ops = {
209 .start = sti_hdmi_tx3g4c28phy_start,
210 .stop = sti_hdmi_tx3g4c28phy_stop,
211};
diff --git a/drivers/gpu/drm/sti/sti_hdmi_tx3g4c28phy.h b/drivers/gpu/drm/sti/sti_hdmi_tx3g4c28phy.h
new file mode 100644
index 000000000000..f99a7ff281ef
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_hdmi_tx3g4c28phy.h
@@ -0,0 +1,14 @@
1/*
2 * Copyright (C) STMicroelectronics SA 2014
3 * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
5 */
6
7#ifndef _STI_HDMI_TX3G4C28PHY_H_
8#define _STI_HDMI_TX3G4C28PHY_H_
9
10#include "sti_hdmi.h"
11
12extern struct hdmi_phy_ops tx3g4c28phy_ops;
13
14#endif
diff --git a/drivers/gpu/drm/sti/sti_layer.c b/drivers/gpu/drm/sti/sti_layer.c
new file mode 100644
index 000000000000..06a587c4f1bb
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_layer.c
@@ -0,0 +1,197 @@
1/*
2 * Copyright (C) STMicroelectronics SA 2014
3 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
4 * Fabien Dessenne <fabien.dessenne@st.com>
5 * for STMicroelectronics.
6 * License terms: GNU General Public License (GPL), version 2
7 */
8
9#include <drm/drmP.h>
10#include <drm/drm_gem_cma_helper.h>
11#include <drm/drm_fb_cma_helper.h>
12
13#include "sti_compositor.h"
14#include "sti_gdp.h"
15#include "sti_layer.h"
16#include "sti_vid.h"
17
18const char *sti_layer_to_str(struct sti_layer *layer)
19{
20 switch (layer->desc) {
21 case STI_GDP_0:
22 return "GDP0";
23 case STI_GDP_1:
24 return "GDP1";
25 case STI_GDP_2:
26 return "GDP2";
27 case STI_GDP_3:
28 return "GDP3";
29 case STI_VID_0:
30 return "VID0";
31 case STI_VID_1:
32 return "VID1";
33 case STI_CURSOR:
34 return "CURSOR";
35 default:
36 return "<UNKNOWN LAYER>";
37 }
38}
39
40struct sti_layer *sti_layer_create(struct device *dev, int desc,
41 void __iomem *baseaddr)
42{
43
44 struct sti_layer *layer = NULL;
45
46 switch (desc & STI_LAYER_TYPE_MASK) {
47 case STI_GDP:
48 layer = sti_gdp_create(dev, desc);
49 break;
50 case STI_VID:
51 layer = sti_vid_create(dev);
52 break;
53 }
54
55 if (!layer) {
56 DRM_ERROR("Failed to create layer\n");
57 return NULL;
58 }
59
60 layer->desc = desc;
61 layer->dev = dev;
62 layer->regs = baseaddr;
63
64 layer->ops->init(layer);
65
66 DRM_DEBUG_DRIVER("%s created\n", sti_layer_to_str(layer));
67
68 return layer;
69}
70
71int sti_layer_prepare(struct sti_layer *layer, struct drm_framebuffer *fb,
72 struct drm_display_mode *mode, int mixer_id,
73 int dest_x, int dest_y, int dest_w, int dest_h,
74 int src_x, int src_y, int src_w, int src_h)
75{
76 int ret;
77 unsigned int i;
78 struct drm_gem_cma_object *cma_obj;
79
80 if (!layer || !fb || !mode) {
81 DRM_ERROR("Null fb, layer or mode\n");
82 return 1;
83 }
84
85 cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
86 if (!cma_obj) {
87 DRM_ERROR("Can't get CMA GEM object for fb\n");
88 return 1;
89 }
90
91 layer->fb = fb;
92 layer->mode = mode;
93 layer->mixer_id = mixer_id;
94 layer->dst_x = dest_x;
95 layer->dst_y = dest_y;
96 layer->dst_w = clamp_val(dest_w, 0, mode->crtc_hdisplay - dest_x);
97 layer->dst_h = clamp_val(dest_h, 0, mode->crtc_vdisplay - dest_y);
98 layer->src_x = src_x;
99 layer->src_y = src_y;
100 layer->src_w = src_w;
101 layer->src_h = src_h;
102 layer->format = fb->pixel_format;
103 layer->paddr = cma_obj->paddr;
104 for (i = 0; i < 4; i++) {
105 layer->pitches[i] = fb->pitches[i];
106 layer->offsets[i] = fb->offsets[i];
107 }
108
109 DRM_DEBUG_DRIVER("%s is associated with mixer_id %d\n",
110 sti_layer_to_str(layer),
111 layer->mixer_id);
112 DRM_DEBUG_DRIVER("%s dst=(%dx%d)@(%d,%d) - src=(%dx%d)@(%d,%d)\n",
113 sti_layer_to_str(layer),
114 layer->dst_w, layer->dst_h, layer->dst_x, layer->dst_y,
115 layer->src_w, layer->src_h, layer->src_x,
116 layer->src_y);
117
118 DRM_DEBUG_DRIVER("drm FB:%d format:%.4s phys@:0x%lx\n", fb->base.id,
119 (char *)&layer->format, (unsigned long)layer->paddr);
120
121 if (!layer->ops->prepare)
122 goto err_no_prepare;
123
124 ret = layer->ops->prepare(layer, !layer->enabled);
125 if (!ret)
126 layer->enabled = true;
127
128 return ret;
129
130err_no_prepare:
131 DRM_ERROR("Cannot prepare\n");
132 return 1;
133}
134
135int sti_layer_commit(struct sti_layer *layer)
136{
137 if (!layer)
138 return 1;
139
140 if (!layer->ops->commit)
141 goto err_no_commit;
142
143 return layer->ops->commit(layer);
144
145err_no_commit:
146 DRM_ERROR("Cannot commit\n");
147 return 1;
148}
149
150int sti_layer_disable(struct sti_layer *layer)
151{
152 int ret;
153
154 DRM_DEBUG_DRIVER("%s\n", sti_layer_to_str(layer));
155 if (!layer)
156 return 1;
157
158 if (!layer->enabled)
159 return 0;
160
161 if (!layer->ops->disable)
162 goto err_no_disable;
163
164 ret = layer->ops->disable(layer);
165 if (!ret)
166 layer->enabled = false;
167 else
168 DRM_ERROR("Disable failed\n");
169
170 return ret;
171
172err_no_disable:
173 DRM_ERROR("Cannot disable\n");
174 return 1;
175}
176
177const uint32_t *sti_layer_get_formats(struct sti_layer *layer)
178{
179 if (!layer)
180 return NULL;
181
182 if (!layer->ops->get_formats)
183 return NULL;
184
185 return layer->ops->get_formats(layer);
186}
187
188unsigned int sti_layer_get_nb_formats(struct sti_layer *layer)
189{
190 if (!layer)
191 return 0;
192
193 if (!layer->ops->get_nb_formats)
194 return 0;
195
196 return layer->ops->get_nb_formats(layer);
197}
diff --git a/drivers/gpu/drm/sti/sti_layer.h b/drivers/gpu/drm/sti/sti_layer.h
new file mode 100644
index 000000000000..198c3774cc12
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_layer.h
@@ -0,0 +1,123 @@
1/*
2 * Copyright (C) STMicroelectronics SA 2014
3 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
4 * Fabien Dessenne <fabien.dessenne@st.com>
5 * for STMicroelectronics.
6 * License terms: GNU General Public License (GPL), version 2
7 */
8
9#ifndef _STI_LAYER_H_
10#define _STI_LAYER_H_
11
12#include <drm/drmP.h>
13
14#define to_sti_layer(x) container_of(x, struct sti_layer, plane)
15
16#define STI_LAYER_TYPE_SHIFT 8
17#define STI_LAYER_TYPE_MASK (~((1<<STI_LAYER_TYPE_SHIFT)-1))
18
19struct sti_layer;
20
21enum sti_layer_type {
22 STI_GDP = 1 << STI_LAYER_TYPE_SHIFT,
23 STI_VID = 2 << STI_LAYER_TYPE_SHIFT,
24 STI_CUR = 3 << STI_LAYER_TYPE_SHIFT,
25 STI_BCK = 4 << STI_LAYER_TYPE_SHIFT
26};
27
28enum sti_layer_id_of_type {
29 STI_ID_0 = 0,
30 STI_ID_1 = 1,
31 STI_ID_2 = 2,
32 STI_ID_3 = 3
33};
34
35enum sti_layer_desc {
36 STI_GDP_0 = STI_GDP | STI_ID_0,
37 STI_GDP_1 = STI_GDP | STI_ID_1,
38 STI_GDP_2 = STI_GDP | STI_ID_2,
39 STI_GDP_3 = STI_GDP | STI_ID_3,
40 STI_VID_0 = STI_VID | STI_ID_0,
41 STI_VID_1 = STI_VID | STI_ID_1,
42 STI_CURSOR = STI_CUR,
43 STI_BACK = STI_BCK
44};
45
46/**
47 * STI layer functions structure
48 *
49 * @get_formats: get layer supported formats
50 * @get_nb_formats: get number of format supported
51 * @init: initialize the layer
52 * @prepare: prepare layer before rendering
53 * @commit: set layer for rendering
54 * @disable: disable layer
55 */
56struct sti_layer_funcs {
57 const uint32_t* (*get_formats)(struct sti_layer *layer);
58 unsigned int (*get_nb_formats)(struct sti_layer *layer);
59 void (*init)(struct sti_layer *layer);
60 int (*prepare)(struct sti_layer *layer, bool first_prepare);
61 int (*commit)(struct sti_layer *layer);
62 int (*disable)(struct sti_layer *layer);
63};
64
65/**
66 * STI layer structure
67 *
68 * @plane: drm plane it is bound to (if any)
69 * @fb: drm fb it is bound to
70 * @mode: display mode
71 * @desc: layer type & id
72 * @device: driver device
73 * @regs: layer registers
74 * @ops: layer functions
75 * @zorder: layer z-order
76 * @mixer_id: id of the mixer used to display the layer
77 * @enabled: to know if the layer is active or not
78 * @src_x src_y: coordinates of the input (fb) area
79 * @src_w src_h: size of the input (fb) area
80 * @dst_x dst_y: coordinates of the output (crtc) area
81 * @dst_w dst_h: size of the output (crtc) area
82 * @format: format
83 * @pitches: pitch of 'planes' (eg: Y, U, V)
84 * @offsets: offset of 'planes'
85 * @paddr: physical address of the input buffer
86 */
87struct sti_layer {
88 struct drm_plane plane;
89 struct drm_framebuffer *fb;
90 struct drm_display_mode *mode;
91 enum sti_layer_desc desc;
92 struct device *dev;
93 void __iomem *regs;
94 const struct sti_layer_funcs *ops;
95 int zorder;
96 int mixer_id;
97 bool enabled;
98 int src_x, src_y;
99 int src_w, src_h;
100 int dst_x, dst_y;
101 int dst_w, dst_h;
102 uint32_t format;
103 unsigned int pitches[4];
104 unsigned int offsets[4];
105 dma_addr_t paddr;
106};
107
108struct sti_layer *sti_layer_create(struct device *dev, int desc,
109 void __iomem *baseaddr);
110int sti_layer_prepare(struct sti_layer *layer, struct drm_framebuffer *fb,
111 struct drm_display_mode *mode,
112 int mixer_id,
113 int dest_x, int dest_y,
114 int dest_w, int dest_h,
115 int src_x, int src_y,
116 int src_w, int src_h);
117int sti_layer_commit(struct sti_layer *layer);
118int sti_layer_disable(struct sti_layer *layer);
119const uint32_t *sti_layer_get_formats(struct sti_layer *layer);
120unsigned int sti_layer_get_nb_formats(struct sti_layer *layer);
121const char *sti_layer_to_str(struct sti_layer *layer);
122
123#endif
diff --git a/drivers/gpu/drm/sti/sti_mixer.c b/drivers/gpu/drm/sti/sti_mixer.c
new file mode 100644
index 000000000000..79f369db9fb6
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_mixer.c
@@ -0,0 +1,249 @@
1/*
2 * Copyright (C) STMicroelectronics SA 2014
3 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
4 * Fabien Dessenne <fabien.dessenne@st.com>
5 * for STMicroelectronics.
6 * License terms: GNU General Public License (GPL), version 2
7 */
8
9#include "sti_compositor.h"
10#include "sti_mixer.h"
11#include "sti_vtg.h"
12
13/* Identity: G=Y , B=Cb , R=Cr */
14static const u32 mixerColorSpaceMatIdentity[] = {
15 0x10000000, 0x00000000, 0x10000000, 0x00001000,
16 0x00000000, 0x00000000, 0x00000000, 0x00000000
17};
18
19/* regs offset */
20#define GAM_MIXER_CTL 0x00
21#define GAM_MIXER_BKC 0x04
22#define GAM_MIXER_BCO 0x0C
23#define GAM_MIXER_BCS 0x10
24#define GAM_MIXER_AVO 0x28
25#define GAM_MIXER_AVS 0x2C
26#define GAM_MIXER_CRB 0x34
27#define GAM_MIXER_ACT 0x38
28#define GAM_MIXER_MBP 0x3C
29#define GAM_MIXER_MX0 0x80
30
31/* id for depth of CRB reg */
32#define GAM_DEPTH_VID0_ID 1
33#define GAM_DEPTH_VID1_ID 2
34#define GAM_DEPTH_GDP0_ID 3
35#define GAM_DEPTH_GDP1_ID 4
36#define GAM_DEPTH_GDP2_ID 5
37#define GAM_DEPTH_GDP3_ID 6
38#define GAM_DEPTH_MASK_ID 7
39
40/* mask in CTL reg */
41#define GAM_CTL_BACK_MASK BIT(0)
42#define GAM_CTL_VID0_MASK BIT(1)
43#define GAM_CTL_VID1_MASK BIT(2)
44#define GAM_CTL_GDP0_MASK BIT(3)
45#define GAM_CTL_GDP1_MASK BIT(4)
46#define GAM_CTL_GDP2_MASK BIT(5)
47#define GAM_CTL_GDP3_MASK BIT(6)
48
49const char *sti_mixer_to_str(struct sti_mixer *mixer)
50{
51 switch (mixer->id) {
52 case STI_MIXER_MAIN:
53 return "MAIN_MIXER";
54 case STI_MIXER_AUX:
55 return "AUX_MIXER";
56 default:
57 return "<UNKNOWN MIXER>";
58 }
59}
60
61static inline u32 sti_mixer_reg_read(struct sti_mixer *mixer, u32 reg_id)
62{
63 return readl(mixer->regs + reg_id);
64}
65
66static inline void sti_mixer_reg_write(struct sti_mixer *mixer,
67 u32 reg_id, u32 val)
68{
69 writel(val, mixer->regs + reg_id);
70}
71
72void sti_mixer_set_background_status(struct sti_mixer *mixer, bool enable)
73{
74 u32 val = sti_mixer_reg_read(mixer, GAM_MIXER_CTL);
75
76 val &= ~GAM_CTL_BACK_MASK;
77 val |= enable;
78 sti_mixer_reg_write(mixer, GAM_MIXER_CTL, val);
79}
80
81static void sti_mixer_set_background_color(struct sti_mixer *mixer,
82 u8 red, u8 green, u8 blue)
83{
84 u32 val = (red << 16) | (green << 8) | blue;
85
86 sti_mixer_reg_write(mixer, GAM_MIXER_BKC, val);
87}
88
89static void sti_mixer_set_background_area(struct sti_mixer *mixer,
90 struct drm_display_mode *mode)
91{
92 u32 ydo, xdo, yds, xds;
93
94 ydo = sti_vtg_get_line_number(*mode, 0);
95 yds = sti_vtg_get_line_number(*mode, mode->vdisplay - 1);
96 xdo = sti_vtg_get_pixel_number(*mode, 0);
97 xds = sti_vtg_get_pixel_number(*mode, mode->hdisplay - 1);
98
99 sti_mixer_reg_write(mixer, GAM_MIXER_BCO, ydo << 16 | xdo);
100 sti_mixer_reg_write(mixer, GAM_MIXER_BCS, yds << 16 | xds);
101}
102
103int sti_mixer_set_layer_depth(struct sti_mixer *mixer, struct sti_layer *layer)
104{
105 int layer_id = 0, depth = layer->zorder;
106 u32 mask, val;
107
108 if (depth >= GAM_MIXER_NB_DEPTH_LEVEL)
109 return 1;
110
111 switch (layer->desc) {
112 case STI_GDP_0:
113 layer_id = GAM_DEPTH_GDP0_ID;
114 break;
115 case STI_GDP_1:
116 layer_id = GAM_DEPTH_GDP1_ID;
117 break;
118 case STI_GDP_2:
119 layer_id = GAM_DEPTH_GDP2_ID;
120 break;
121 case STI_GDP_3:
122 layer_id = GAM_DEPTH_GDP3_ID;
123 break;
124 case STI_VID_0:
125 layer_id = GAM_DEPTH_VID0_ID;
126 break;
127 case STI_VID_1:
128 layer_id = GAM_DEPTH_VID1_ID;
129 break;
130 default:
131 DRM_ERROR("Unknown layer %d\n", layer->desc);
132 return 1;
133 }
134 mask = GAM_DEPTH_MASK_ID << (3 * depth);
135 layer_id = layer_id << (3 * depth);
136
137 DRM_DEBUG_DRIVER("%s %s depth=%d\n", sti_mixer_to_str(mixer),
138 sti_layer_to_str(layer), depth);
139 dev_dbg(mixer->dev, "GAM_MIXER_CRB val 0x%x mask 0x%x\n",
140 layer_id, mask);
141
142 val = sti_mixer_reg_read(mixer, GAM_MIXER_CRB);
143 val &= ~mask;
144 val |= layer_id;
145 sti_mixer_reg_write(mixer, GAM_MIXER_CRB, val);
146
147 dev_dbg(mixer->dev, "Read GAM_MIXER_CRB 0x%x\n",
148 sti_mixer_reg_read(mixer, GAM_MIXER_CRB));
149 return 0;
150}
151
152int sti_mixer_active_video_area(struct sti_mixer *mixer,
153 struct drm_display_mode *mode)
154{
155 u32 ydo, xdo, yds, xds;
156
157 ydo = sti_vtg_get_line_number(*mode, 0);
158 yds = sti_vtg_get_line_number(*mode, mode->vdisplay - 1);
159 xdo = sti_vtg_get_pixel_number(*mode, 0);
160 xds = sti_vtg_get_pixel_number(*mode, mode->hdisplay - 1);
161
162 DRM_DEBUG_DRIVER("%s active video area xdo:%d ydo:%d xds:%d yds:%d\n",
163 sti_mixer_to_str(mixer), xdo, ydo, xds, yds);
164 sti_mixer_reg_write(mixer, GAM_MIXER_AVO, ydo << 16 | xdo);
165 sti_mixer_reg_write(mixer, GAM_MIXER_AVS, yds << 16 | xds);
166
167 sti_mixer_set_background_color(mixer, 0xFF, 0, 0);
168
169 sti_mixer_set_background_area(mixer, mode);
170 sti_mixer_set_background_status(mixer, true);
171 return 0;
172}
173
174static u32 sti_mixer_get_layer_mask(struct sti_layer *layer)
175{
176 switch (layer->desc) {
177 case STI_BACK:
178 return GAM_CTL_BACK_MASK;
179 case STI_GDP_0:
180 return GAM_CTL_GDP0_MASK;
181 case STI_GDP_1:
182 return GAM_CTL_GDP1_MASK;
183 case STI_GDP_2:
184 return GAM_CTL_GDP2_MASK;
185 case STI_GDP_3:
186 return GAM_CTL_GDP3_MASK;
187 case STI_VID_0:
188 return GAM_CTL_VID0_MASK;
189 case STI_VID_1:
190 return GAM_CTL_VID1_MASK;
191 default:
192 return 0;
193 }
194}
195
196int sti_mixer_set_layer_status(struct sti_mixer *mixer,
197 struct sti_layer *layer, bool status)
198{
199 u32 mask, val;
200
201 DRM_DEBUG_DRIVER("%s %s %s\n", status ? "enable" : "disable",
202 sti_mixer_to_str(mixer), sti_layer_to_str(layer));
203
204 mask = sti_mixer_get_layer_mask(layer);
205 if (!mask) {
206 DRM_ERROR("Can not find layer mask\n");
207 return -EINVAL;
208 }
209
210 val = sti_mixer_reg_read(mixer, GAM_MIXER_CTL);
211 val &= ~mask;
212 val |= status ? mask : 0;
213 sti_mixer_reg_write(mixer, GAM_MIXER_CTL, val);
214
215 return 0;
216}
217
218void sti_mixer_set_matrix(struct sti_mixer *mixer)
219{
220 unsigned int i;
221
222 for (i = 0; i < ARRAY_SIZE(mixerColorSpaceMatIdentity); i++)
223 sti_mixer_reg_write(mixer, GAM_MIXER_MX0 + (i * 4),
224 mixerColorSpaceMatIdentity[i]);
225}
226
227struct sti_mixer *sti_mixer_create(struct device *dev, int id,
228 void __iomem *baseaddr)
229{
230 struct sti_mixer *mixer = devm_kzalloc(dev, sizeof(*mixer), GFP_KERNEL);
231 struct device_node *np = dev->of_node;
232
233 dev_dbg(dev, "%s\n", __func__);
234 if (!mixer) {
235 DRM_ERROR("Failed to allocated memory for mixer\n");
236 return NULL;
237 }
238 mixer->regs = baseaddr;
239 mixer->dev = dev;
240 mixer->id = id;
241
242 if (of_device_is_compatible(np, "st,stih416-compositor"))
243 sti_mixer_set_matrix(mixer);
244
245 DRM_DEBUG_DRIVER("%s created. Regs=%p\n",
246 sti_mixer_to_str(mixer), mixer->regs);
247
248 return mixer;
249}
diff --git a/drivers/gpu/drm/sti/sti_mixer.h b/drivers/gpu/drm/sti/sti_mixer.h
new file mode 100644
index 000000000000..874372102e52
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_mixer.h
@@ -0,0 +1,54 @@
1/*
2 * Copyright (C) STMicroelectronics SA 2014
3 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
4 * Fabien Dessenne <fabien.dessenne@st.com>
5 * for STMicroelectronics.
6 * License terms: GNU General Public License (GPL), version 2
7 */
8
9#ifndef _STI_MIXER_H_
10#define _STI_MIXER_H_
11
12#include <drm/drmP.h>
13
14#include "sti_layer.h"
15
16#define to_sti_mixer(x) container_of(x, struct sti_mixer, drm_crtc)
17
18/**
19 * STI Mixer subdevice structure
20 *
21 * @dev: driver device
22 * @regs: mixer registers
23 * @id: id of the mixer
24 * @drm_crtc: crtc object link to the mixer
25 * @pending_event: set if a flip event is pending on crtc
26 */
27struct sti_mixer {
28 struct device *dev;
29 void __iomem *regs;
30 int id;
31 struct drm_crtc drm_crtc;
32 struct drm_pending_vblank_event *pending_event;
33};
34
35const char *sti_mixer_to_str(struct sti_mixer *mixer);
36
37struct sti_mixer *sti_mixer_create(struct device *dev, int id,
38 void __iomem *baseaddr);
39
40int sti_mixer_set_layer_status(struct sti_mixer *mixer,
41 struct sti_layer *layer, bool status);
42int sti_mixer_set_layer_depth(struct sti_mixer *mixer, struct sti_layer *layer);
43int sti_mixer_active_video_area(struct sti_mixer *mixer,
44 struct drm_display_mode *mode);
45
46void sti_mixer_set_background_status(struct sti_mixer *mixer, bool enable);
47
48/* depth in Cross-bar control = z order */
49#define GAM_MIXER_NB_DEPTH_LEVEL 7
50
51#define STI_MIXER_MAIN 0
52#define STI_MIXER_AUX 1
53
54#endif
diff --git a/drivers/gpu/drm/sti/sti_tvout.c b/drivers/gpu/drm/sti/sti_tvout.c
new file mode 100644
index 000000000000..b69e26fee76e
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_tvout.c
@@ -0,0 +1,648 @@
1/*
2 * Copyright (C) STMicroelectronics SA 2014
3 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
4 * Vincent Abriou <vincent.abriou@st.com>
5 * for STMicroelectronics.
6 * License terms: GNU General Public License (GPL), version 2
7 */
8
9#include <linux/clk.h>
10#include <linux/component.h>
11#include <linux/module.h>
12#include <linux/of_platform.h>
13#include <linux/platform_device.h>
14#include <linux/reset.h>
15
16#include <drm/drmP.h>
17#include <drm/drm_crtc_helper.h>
18
19/* glue registers */
20#define TVO_CSC_MAIN_M0 0x000
21#define TVO_CSC_MAIN_M1 0x004
22#define TVO_CSC_MAIN_M2 0x008
23#define TVO_CSC_MAIN_M3 0x00c
24#define TVO_CSC_MAIN_M4 0x010
25#define TVO_CSC_MAIN_M5 0x014
26#define TVO_CSC_MAIN_M6 0x018
27#define TVO_CSC_MAIN_M7 0x01c
28#define TVO_MAIN_IN_VID_FORMAT 0x030
29#define TVO_CSC_AUX_M0 0x100
30#define TVO_CSC_AUX_M1 0x104
31#define TVO_CSC_AUX_M2 0x108
32#define TVO_CSC_AUX_M3 0x10c
33#define TVO_CSC_AUX_M4 0x110
34#define TVO_CSC_AUX_M5 0x114
35#define TVO_CSC_AUX_M6 0x118
36#define TVO_CSC_AUX_M7 0x11c
37#define TVO_AUX_IN_VID_FORMAT 0x130
38#define TVO_VIP_HDF 0x400
39#define TVO_HD_SYNC_SEL 0x418
40#define TVO_HD_DAC_CFG_OFF 0x420
41#define TVO_VIP_HDMI 0x500
42#define TVO_HDMI_FORCE_COLOR_0 0x504
43#define TVO_HDMI_FORCE_COLOR_1 0x508
44#define TVO_HDMI_CLIP_VALUE_B_CB 0x50c
45#define TVO_HDMI_CLIP_VALUE_Y_G 0x510
46#define TVO_HDMI_CLIP_VALUE_R_CR 0x514
47#define TVO_HDMI_SYNC_SEL 0x518
48#define TVO_HDMI_DFV_OBS 0x540
49
50#define TVO_IN_FMT_SIGNED BIT(0)
51#define TVO_SYNC_EXT BIT(4)
52
53#define TVO_VIP_REORDER_R_SHIFT 24
54#define TVO_VIP_REORDER_G_SHIFT 20
55#define TVO_VIP_REORDER_B_SHIFT 16
56#define TVO_VIP_REORDER_MASK 0x3
57#define TVO_VIP_REORDER_Y_G_SEL 0
58#define TVO_VIP_REORDER_CB_B_SEL 1
59#define TVO_VIP_REORDER_CR_R_SEL 2
60
61#define TVO_VIP_CLIP_SHIFT 8
62#define TVO_VIP_CLIP_MASK 0x7
63#define TVO_VIP_CLIP_DISABLED 0
64#define TVO_VIP_CLIP_EAV_SAV 1
65#define TVO_VIP_CLIP_LIMITED_RANGE_RGB_Y 2
66#define TVO_VIP_CLIP_LIMITED_RANGE_CB_CR 3
67#define TVO_VIP_CLIP_PROG_RANGE 4
68
69#define TVO_VIP_RND_SHIFT 4
70#define TVO_VIP_RND_MASK 0x3
71#define TVO_VIP_RND_8BIT_ROUNDED 0
72#define TVO_VIP_RND_10BIT_ROUNDED 1
73#define TVO_VIP_RND_12BIT_ROUNDED 2
74
75#define TVO_VIP_SEL_INPUT_MASK 0xf
76#define TVO_VIP_SEL_INPUT_MAIN 0x0
77#define TVO_VIP_SEL_INPUT_AUX 0x8
78#define TVO_VIP_SEL_INPUT_FORCE_COLOR 0xf
79#define TVO_VIP_SEL_INPUT_BYPASS_MASK 0x1
80#define TVO_VIP_SEL_INPUT_BYPASSED 1
81
82#define TVO_SYNC_MAIN_VTG_SET_REF 0x00
83#define TVO_SYNC_MAIN_VTG_SET_1 0x01
84#define TVO_SYNC_MAIN_VTG_SET_2 0x02
85#define TVO_SYNC_MAIN_VTG_SET_3 0x03
86#define TVO_SYNC_MAIN_VTG_SET_4 0x04
87#define TVO_SYNC_MAIN_VTG_SET_5 0x05
88#define TVO_SYNC_MAIN_VTG_SET_6 0x06
89#define TVO_SYNC_AUX_VTG_SET_REF 0x10
90#define TVO_SYNC_AUX_VTG_SET_1 0x11
91#define TVO_SYNC_AUX_VTG_SET_2 0x12
92#define TVO_SYNC_AUX_VTG_SET_3 0x13
93#define TVO_SYNC_AUX_VTG_SET_4 0x14
94#define TVO_SYNC_AUX_VTG_SET_5 0x15
95#define TVO_SYNC_AUX_VTG_SET_6 0x16
96
97#define TVO_SYNC_HD_DCS_SHIFT 8
98
99#define ENCODER_MAIN_CRTC_MASK BIT(0)
100
101/* enum listing the supported output data format */
102enum sti_tvout_video_out_type {
103 STI_TVOUT_VIDEO_OUT_RGB,
104 STI_TVOUT_VIDEO_OUT_YUV,
105};
106
107struct sti_tvout {
108 struct device *dev;
109 struct drm_device *drm_dev;
110 void __iomem *regs;
111 struct reset_control *reset;
112 struct drm_encoder *hdmi;
113 struct drm_encoder *hda;
114};
115
116struct sti_tvout_encoder {
117 struct drm_encoder encoder;
118 struct sti_tvout *tvout;
119};
120
121#define to_sti_tvout_encoder(x) \
122 container_of(x, struct sti_tvout_encoder, encoder)
123
124#define to_sti_tvout(x) to_sti_tvout_encoder(x)->tvout
125
126/* preformatter conversion matrix */
127static const u32 rgb_to_ycbcr_601[8] = {
128 0xF927082E, 0x04C9FEAB, 0x01D30964, 0xFA95FD3D,
129 0x0000082E, 0x00002000, 0x00002000, 0x00000000
130};
131
132/* 709 RGB to YCbCr */
133static const u32 rgb_to_ycbcr_709[8] = {
134 0xF891082F, 0x0367FF40, 0x01280B71, 0xF9B1FE20,
135 0x0000082F, 0x00002000, 0x00002000, 0x00000000
136};
137
138static u32 tvout_read(struct sti_tvout *tvout, int offset)
139{
140 return readl(tvout->regs + offset);
141}
142
143static void tvout_write(struct sti_tvout *tvout, u32 val, int offset)
144{
145 writel(val, tvout->regs + offset);
146}
147
148/**
149 * Set the clipping mode of a VIP
150 *
151 * @tvout: tvout structure
152 * @cr_r:
153 * @y_g:
154 * @cb_b:
155 */
156static void tvout_vip_set_color_order(struct sti_tvout *tvout,
157 u32 cr_r, u32 y_g, u32 cb_b)
158{
159 u32 val = tvout_read(tvout, TVO_VIP_HDMI);
160
161 val &= ~(TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_R_SHIFT);
162 val &= ~(TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_G_SHIFT);
163 val &= ~(TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_B_SHIFT);
164 val |= cr_r << TVO_VIP_REORDER_R_SHIFT;
165 val |= y_g << TVO_VIP_REORDER_G_SHIFT;
166 val |= cb_b << TVO_VIP_REORDER_B_SHIFT;
167
168 tvout_write(tvout, val, TVO_VIP_HDMI);
169}
170
171/**
172 * Set the clipping mode of a VIP
173 *
174 * @tvout: tvout structure
175 * @range: clipping range
176 */
177static void tvout_vip_set_clip_mode(struct sti_tvout *tvout, u32 range)
178{
179 u32 val = tvout_read(tvout, TVO_VIP_HDMI);
180
181 val &= ~(TVO_VIP_CLIP_MASK << TVO_VIP_CLIP_SHIFT);
182 val |= range << TVO_VIP_CLIP_SHIFT;
183 tvout_write(tvout, val, TVO_VIP_HDMI);
184}
185
186/**
187 * Set the rounded value of a VIP
188 *
189 * @tvout: tvout structure
190 * @rnd: rounded val per component
191 */
192static void tvout_vip_set_rnd(struct sti_tvout *tvout, u32 rnd)
193{
194 u32 val = tvout_read(tvout, TVO_VIP_HDMI);
195
196 val &= ~(TVO_VIP_RND_MASK << TVO_VIP_RND_SHIFT);
197 val |= rnd << TVO_VIP_RND_SHIFT;
198 tvout_write(tvout, val, TVO_VIP_HDMI);
199}
200
201/**
202 * Select the VIP input
203 *
204 * @tvout: tvout structure
205 * @sel_input: selected_input (main/aux + conv)
206 */
207static void tvout_vip_set_sel_input(struct sti_tvout *tvout,
208 bool main_path,
209 bool sel_input_logic_inverted,
210 enum sti_tvout_video_out_type video_out)
211{
212 u32 sel_input;
213 u32 val = tvout_read(tvout, TVO_VIP_HDMI);
214
215 if (main_path)
216 sel_input = TVO_VIP_SEL_INPUT_MAIN;
217 else
218 sel_input = TVO_VIP_SEL_INPUT_AUX;
219
220 switch (video_out) {
221 case STI_TVOUT_VIDEO_OUT_RGB:
222 sel_input |= TVO_VIP_SEL_INPUT_BYPASSED;
223 break;
224 case STI_TVOUT_VIDEO_OUT_YUV:
225 sel_input &= ~TVO_VIP_SEL_INPUT_BYPASSED;
226 break;
227 }
228
229 /* on stih407 chip the sel_input bypass mode logic is inverted */
230 if (sel_input_logic_inverted)
231 sel_input = sel_input ^ TVO_VIP_SEL_INPUT_BYPASS_MASK;
232
233 val &= ~TVO_VIP_SEL_INPUT_MASK;
234 val |= sel_input;
235 tvout_write(tvout, val, TVO_VIP_HDMI);
236}
237
238/**
239 * Select the input video signed or unsigned
240 *
241 * @tvout: tvout structure
242 * @in_vid_signed: used video input format
243 */
244static void tvout_vip_set_in_vid_fmt(struct sti_tvout *tvout, u32 in_vid_fmt)
245{
246 u32 val = tvout_read(tvout, TVO_VIP_HDMI);
247
248 val &= ~TVO_IN_FMT_SIGNED;
249 val |= in_vid_fmt;
250 tvout_write(tvout, val, TVO_MAIN_IN_VID_FORMAT);
251}
252
253/**
254 * Start VIP block for HDMI output
255 *
256 * @tvout: pointer on tvout structure
257 * @main_path: true if main path has to be used in the vip configuration
258 * else aux path is used.
259 */
260static void tvout_hdmi_start(struct sti_tvout *tvout, bool main_path)
261{
262 struct device_node *node = tvout->dev->of_node;
263 bool sel_input_logic_inverted = false;
264
265 dev_dbg(tvout->dev, "%s\n", __func__);
266
267 if (main_path) {
268 DRM_DEBUG_DRIVER("main vip for hdmi\n");
269 /* select the input sync for hdmi = VTG set 1 */
270 tvout_write(tvout, TVO_SYNC_MAIN_VTG_SET_1, TVO_HDMI_SYNC_SEL);
271 } else {
272 DRM_DEBUG_DRIVER("aux vip for hdmi\n");
273 /* select the input sync for hdmi = VTG set 1 */
274 tvout_write(tvout, TVO_SYNC_AUX_VTG_SET_1, TVO_HDMI_SYNC_SEL);
275 }
276
277 /* set color channel order */
278 tvout_vip_set_color_order(tvout,
279 TVO_VIP_REORDER_CR_R_SEL,
280 TVO_VIP_REORDER_Y_G_SEL,
281 TVO_VIP_REORDER_CB_B_SEL);
282
283 /* set clipping mode (Limited range RGB/Y) */
284 tvout_vip_set_clip_mode(tvout, TVO_VIP_CLIP_LIMITED_RANGE_RGB_Y);
285
286 /* set round mode (rounded to 8-bit per component) */
287 tvout_vip_set_rnd(tvout, TVO_VIP_RND_8BIT_ROUNDED);
288
289 if (of_device_is_compatible(node, "st,stih407-tvout")) {
290 /* set input video format */
291 tvout_vip_set_in_vid_fmt(tvout->regs + TVO_MAIN_IN_VID_FORMAT,
292 TVO_IN_FMT_SIGNED);
293 sel_input_logic_inverted = true;
294 }
295
296 /* input selection */
297 tvout_vip_set_sel_input(tvout, main_path,
298 sel_input_logic_inverted, STI_TVOUT_VIDEO_OUT_RGB);
299}
300
301/**
302 * Start HDF VIP and HD DAC
303 *
304 * @tvout: pointer on tvout structure
305 * @main_path: true if main path has to be used in the vip configuration
306 * else aux path is used.
307 */
308static void tvout_hda_start(struct sti_tvout *tvout, bool main_path)
309{
310 struct device_node *node = tvout->dev->of_node;
311 bool sel_input_logic_inverted = false;
312
313 dev_dbg(tvout->dev, "%s\n", __func__);
314
315 if (!main_path) {
316 DRM_ERROR("HD Analog on aux not implemented\n");
317 return;
318 }
319
320 DRM_DEBUG_DRIVER("main vip for HDF\n");
321
322 /* set color channel order */
323 tvout_vip_set_color_order(tvout->regs + TVO_VIP_HDF,
324 TVO_VIP_REORDER_CR_R_SEL,
325 TVO_VIP_REORDER_Y_G_SEL,
326 TVO_VIP_REORDER_CB_B_SEL);
327
328 /* set clipping mode (Limited range RGB/Y) */
329 tvout_vip_set_clip_mode(tvout->regs + TVO_VIP_HDF,
330 TVO_VIP_CLIP_LIMITED_RANGE_CB_CR);
331
332 /* set round mode (rounded to 10-bit per component) */
333 tvout_vip_set_rnd(tvout->regs + TVO_VIP_HDF, TVO_VIP_RND_10BIT_ROUNDED);
334
335 if (of_device_is_compatible(node, "st,stih407-tvout")) {
336 /* set input video format */
337 tvout_vip_set_in_vid_fmt(tvout, TVO_IN_FMT_SIGNED);
338 sel_input_logic_inverted = true;
339 }
340
341 /* Input selection */
342 tvout_vip_set_sel_input(tvout->regs + TVO_VIP_HDF,
343 main_path,
344 sel_input_logic_inverted,
345 STI_TVOUT_VIDEO_OUT_YUV);
346
347 /* select the input sync for HD analog = VTG set 3
348 * and HD DCS = VTG set 2 */
349 tvout_write(tvout,
350 (TVO_SYNC_MAIN_VTG_SET_2 << TVO_SYNC_HD_DCS_SHIFT)
351 | TVO_SYNC_MAIN_VTG_SET_3,
352 TVO_HD_SYNC_SEL);
353
354 /* power up HD DAC */
355 tvout_write(tvout, 0, TVO_HD_DAC_CFG_OFF);
356}
357
358static void sti_tvout_encoder_dpms(struct drm_encoder *encoder, int mode)
359{
360}
361
362static bool sti_tvout_encoder_mode_fixup(struct drm_encoder *encoder,
363 const struct drm_display_mode *mode,
364 struct drm_display_mode *adjusted_mode)
365{
366 return true;
367}
368
369static void sti_tvout_encoder_mode_set(struct drm_encoder *encoder,
370 struct drm_display_mode *mode,
371 struct drm_display_mode *adjusted_mode)
372{
373}
374
375static void sti_tvout_encoder_prepare(struct drm_encoder *encoder)
376{
377}
378
379static void sti_tvout_encoder_destroy(struct drm_encoder *encoder)
380{
381 struct sti_tvout_encoder *sti_encoder = to_sti_tvout_encoder(encoder);
382
383 drm_encoder_cleanup(encoder);
384 kfree(sti_encoder);
385}
386
387static const struct drm_encoder_funcs sti_tvout_encoder_funcs = {
388 .destroy = sti_tvout_encoder_destroy,
389};
390
391static void sti_hda_encoder_commit(struct drm_encoder *encoder)
392{
393 struct sti_tvout *tvout = to_sti_tvout(encoder);
394
395 tvout_hda_start(tvout, true);
396}
397
398static void sti_hda_encoder_disable(struct drm_encoder *encoder)
399{
400 struct sti_tvout *tvout = to_sti_tvout(encoder);
401
402 /* reset VIP register */
403 tvout_write(tvout, 0x0, TVO_VIP_HDF);
404
405 /* power down HD DAC */
406 tvout_write(tvout, 1, TVO_HD_DAC_CFG_OFF);
407}
408
409static const struct drm_encoder_helper_funcs sti_hda_encoder_helper_funcs = {
410 .dpms = sti_tvout_encoder_dpms,
411 .mode_fixup = sti_tvout_encoder_mode_fixup,
412 .mode_set = sti_tvout_encoder_mode_set,
413 .prepare = sti_tvout_encoder_prepare,
414 .commit = sti_hda_encoder_commit,
415 .disable = sti_hda_encoder_disable,
416};
417
418static struct drm_encoder *sti_tvout_create_hda_encoder(struct drm_device *dev,
419 struct sti_tvout *tvout)
420{
421 struct sti_tvout_encoder *encoder;
422 struct drm_encoder *drm_encoder;
423
424 encoder = devm_kzalloc(tvout->dev, sizeof(*encoder), GFP_KERNEL);
425 if (!encoder)
426 return NULL;
427
428 encoder->tvout = tvout;
429
430 drm_encoder = (struct drm_encoder *) encoder;
431
432 drm_encoder->possible_crtcs = ENCODER_MAIN_CRTC_MASK;
433 drm_encoder->possible_clones = 1 << 0;
434
435 drm_encoder_init(dev, drm_encoder,
436 &sti_tvout_encoder_funcs, DRM_MODE_ENCODER_DAC);
437
438 drm_encoder_helper_add(drm_encoder, &sti_hda_encoder_helper_funcs);
439
440 return drm_encoder;
441}
442
443static void sti_hdmi_encoder_commit(struct drm_encoder *encoder)
444{
445 struct sti_tvout *tvout = to_sti_tvout(encoder);
446
447 tvout_hdmi_start(tvout, true);
448}
449
450static void sti_hdmi_encoder_disable(struct drm_encoder *encoder)
451{
452 struct sti_tvout *tvout = to_sti_tvout(encoder);
453
454 /* reset VIP register */
455 tvout_write(tvout, 0x0, TVO_VIP_HDMI);
456}
457
458static const struct drm_encoder_helper_funcs sti_hdmi_encoder_helper_funcs = {
459 .dpms = sti_tvout_encoder_dpms,
460 .mode_fixup = sti_tvout_encoder_mode_fixup,
461 .mode_set = sti_tvout_encoder_mode_set,
462 .prepare = sti_tvout_encoder_prepare,
463 .commit = sti_hdmi_encoder_commit,
464 .disable = sti_hdmi_encoder_disable,
465};
466
467static struct drm_encoder *sti_tvout_create_hdmi_encoder(struct drm_device *dev,
468 struct sti_tvout *tvout)
469{
470 struct sti_tvout_encoder *encoder;
471 struct drm_encoder *drm_encoder;
472
473 encoder = devm_kzalloc(tvout->dev, sizeof(*encoder), GFP_KERNEL);
474 if (!encoder)
475 return NULL;
476
477 encoder->tvout = tvout;
478
479 drm_encoder = (struct drm_encoder *) encoder;
480
481 drm_encoder->possible_crtcs = ENCODER_MAIN_CRTC_MASK;
482 drm_encoder->possible_clones = 1 << 1;
483
484 drm_encoder_init(dev, drm_encoder,
485 &sti_tvout_encoder_funcs, DRM_MODE_ENCODER_TMDS);
486
487 drm_encoder_helper_add(drm_encoder, &sti_hdmi_encoder_helper_funcs);
488
489 return drm_encoder;
490}
491
492static void sti_tvout_create_encoders(struct drm_device *dev,
493 struct sti_tvout *tvout)
494{
495 tvout->hdmi = sti_tvout_create_hdmi_encoder(dev, tvout);
496 tvout->hda = sti_tvout_create_hda_encoder(dev, tvout);
497}
498
499static void sti_tvout_destroy_encoders(struct sti_tvout *tvout)
500{
501 if (tvout->hdmi)
502 drm_encoder_cleanup(tvout->hdmi);
503 tvout->hdmi = NULL;
504
505 if (tvout->hda)
506 drm_encoder_cleanup(tvout->hda);
507 tvout->hda = NULL;
508}
509
510static int sti_tvout_bind(struct device *dev, struct device *master, void *data)
511{
512 struct sti_tvout *tvout = dev_get_drvdata(dev);
513 struct drm_device *drm_dev = data;
514 unsigned int i;
515 int ret;
516
517 tvout->drm_dev = drm_dev;
518
519 /* set preformatter matrix */
520 for (i = 0; i < 8; i++) {
521 tvout_write(tvout, rgb_to_ycbcr_601[i],
522 TVO_CSC_MAIN_M0 + (i * 4));
523 tvout_write(tvout, rgb_to_ycbcr_601[i],
524 TVO_CSC_AUX_M0 + (i * 4));
525 }
526
527 sti_tvout_create_encoders(drm_dev, tvout);
528
529 ret = component_bind_all(dev, drm_dev);
530 if (ret)
531 sti_tvout_destroy_encoders(tvout);
532
533 return ret;
534}
535
536static void sti_tvout_unbind(struct device *dev, struct device *master,
537 void *data)
538{
539 /* do nothing */
540}
541
542static const struct component_ops sti_tvout_ops = {
543 .bind = sti_tvout_bind,
544 .unbind = sti_tvout_unbind,
545};
546
547static int compare_of(struct device *dev, void *data)
548{
549 return dev->of_node == data;
550}
551
552static int sti_tvout_master_bind(struct device *dev)
553{
554 return 0;
555}
556
557static void sti_tvout_master_unbind(struct device *dev)
558{
559 /* do nothing */
560}
561
562static const struct component_master_ops sti_tvout_master_ops = {
563 .bind = sti_tvout_master_bind,
564 .unbind = sti_tvout_master_unbind,
565};
566
567static int sti_tvout_probe(struct platform_device *pdev)
568{
569 struct device *dev = &pdev->dev;
570 struct device_node *node = dev->of_node;
571 struct sti_tvout *tvout;
572 struct resource *res;
573 struct device_node *child_np;
574 struct component_match *match = NULL;
575
576 DRM_INFO("%s\n", __func__);
577
578 if (!node)
579 return -ENODEV;
580
581 tvout = devm_kzalloc(dev, sizeof(*tvout), GFP_KERNEL);
582 if (!tvout)
583 return -ENOMEM;
584
585 tvout->dev = dev;
586
587 /* get Memory ressources */
588 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tvout-reg");
589 if (!res) {
590 DRM_ERROR("Invalid glue resource\n");
591 return -ENOMEM;
592 }
593 tvout->regs = devm_ioremap_nocache(dev, res->start, resource_size(res));
594 if (IS_ERR(tvout->regs))
595 return PTR_ERR(tvout->regs);
596
597 /* get reset resources */
598 tvout->reset = devm_reset_control_get(dev, "tvout");
599 /* take tvout out of reset */
600 if (!IS_ERR(tvout->reset))
601 reset_control_deassert(tvout->reset);
602
603 platform_set_drvdata(pdev, tvout);
604
605 of_platform_populate(node, NULL, NULL, dev);
606
607 child_np = of_get_next_available_child(node, NULL);
608
609 while (child_np) {
610 component_match_add(dev, &match, compare_of, child_np);
611 of_node_put(child_np);
612 child_np = of_get_next_available_child(node, child_np);
613 }
614
615 component_master_add_with_match(dev, &sti_tvout_master_ops, match);
616
617 return component_add(dev, &sti_tvout_ops);
618}
619
620static int sti_tvout_remove(struct platform_device *pdev)
621{
622 component_master_del(&pdev->dev, &sti_tvout_master_ops);
623 component_del(&pdev->dev, &sti_tvout_ops);
624 return 0;
625}
626
627static struct of_device_id tvout_of_match[] = {
628 { .compatible = "st,stih416-tvout", },
629 { .compatible = "st,stih407-tvout", },
630 { /* end node */ }
631};
632MODULE_DEVICE_TABLE(of, tvout_of_match);
633
634struct platform_driver sti_tvout_driver = {
635 .driver = {
636 .name = "sti-tvout",
637 .owner = THIS_MODULE,
638 .of_match_table = tvout_of_match,
639 },
640 .probe = sti_tvout_probe,
641 .remove = sti_tvout_remove,
642};
643
644module_platform_driver(sti_tvout_driver);
645
646MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
647MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
648MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/sti/sti_vid.c b/drivers/gpu/drm/sti/sti_vid.c
new file mode 100644
index 000000000000..10ced6a479f4
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_vid.c
@@ -0,0 +1,138 @@
1/*
2 * Copyright (C) STMicroelectronics SA 2014
3 * Author: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
5 */
6
7#include <drm/drmP.h>
8
9#include "sti_layer.h"
10#include "sti_vid.h"
11#include "sti_vtg.h"
12
13/* Registers */
14#define VID_CTL 0x00
15#define VID_ALP 0x04
16#define VID_CLF 0x08
17#define VID_VPO 0x0C
18#define VID_VPS 0x10
19#define VID_KEY1 0x28
20#define VID_KEY2 0x2C
21#define VID_MPR0 0x30
22#define VID_MPR1 0x34
23#define VID_MPR2 0x38
24#define VID_MPR3 0x3C
25#define VID_MST 0x68
26#define VID_BC 0x70
27#define VID_TINT 0x74
28#define VID_CSAT 0x78
29
30/* Registers values */
31#define VID_CTL_IGNORE (BIT(31) | BIT(30))
32#define VID_CTL_PSI_ENABLE (BIT(2) | BIT(1) | BIT(0))
33#define VID_ALP_OPAQUE 0x00000080
34#define VID_BC_DFLT 0x00008000
35#define VID_TINT_DFLT 0x00000000
36#define VID_CSAT_DFLT 0x00000080
37/* YCbCr to RGB BT709:
38 * R = Y+1.5391Cr
39 * G = Y-0.4590Cr-0.1826Cb
40 * B = Y+1.8125Cb */
41#define VID_MPR0_BT709 0x0A800000
42#define VID_MPR1_BT709 0x0AC50000
43#define VID_MPR2_BT709 0x07150545
44#define VID_MPR3_BT709 0x00000AE8
45
46static int sti_vid_prepare_layer(struct sti_layer *vid, bool first_prepare)
47{
48 u32 val;
49
50 /* Unmask */
51 val = readl(vid->regs + VID_CTL);
52 val &= ~VID_CTL_IGNORE;
53 writel(val, vid->regs + VID_CTL);
54
55 return 0;
56}
57
58static int sti_vid_commit_layer(struct sti_layer *vid)
59{
60 struct drm_display_mode *mode = vid->mode;
61 u32 ydo, xdo, yds, xds;
62
63 ydo = sti_vtg_get_line_number(*mode, vid->dst_y);
64 yds = sti_vtg_get_line_number(*mode, vid->dst_y + vid->dst_h - 1);
65 xdo = sti_vtg_get_pixel_number(*mode, vid->dst_x);
66 xds = sti_vtg_get_pixel_number(*mode, vid->dst_x + vid->dst_w - 1);
67
68 writel((ydo << 16) | xdo, vid->regs + VID_VPO);
69 writel((yds << 16) | xds, vid->regs + VID_VPS);
70
71 return 0;
72}
73
74static int sti_vid_disable_layer(struct sti_layer *vid)
75{
76 u32 val;
77
78 /* Mask */
79 val = readl(vid->regs + VID_CTL);
80 val |= VID_CTL_IGNORE;
81 writel(val, vid->regs + VID_CTL);
82
83 return 0;
84}
85
86static const uint32_t *sti_vid_get_formats(struct sti_layer *layer)
87{
88 return NULL;
89}
90
91static unsigned int sti_vid_get_nb_formats(struct sti_layer *layer)
92{
93 return 0;
94}
95
96static void sti_vid_init(struct sti_layer *vid)
97{
98 /* Enable PSI, Mask layer */
99 writel(VID_CTL_PSI_ENABLE | VID_CTL_IGNORE, vid->regs + VID_CTL);
100
101 /* Opaque */
102 writel(VID_ALP_OPAQUE, vid->regs + VID_ALP);
103
104 /* Color conversion parameters */
105 writel(VID_MPR0_BT709, vid->regs + VID_MPR0);
106 writel(VID_MPR1_BT709, vid->regs + VID_MPR1);
107 writel(VID_MPR2_BT709, vid->regs + VID_MPR2);
108 writel(VID_MPR3_BT709, vid->regs + VID_MPR3);
109
110 /* Brightness, contrast, tint, saturation */
111 writel(VID_BC_DFLT, vid->regs + VID_BC);
112 writel(VID_TINT_DFLT, vid->regs + VID_TINT);
113 writel(VID_CSAT_DFLT, vid->regs + VID_CSAT);
114}
115
116static const struct sti_layer_funcs vid_ops = {
117 .get_formats = sti_vid_get_formats,
118 .get_nb_formats = sti_vid_get_nb_formats,
119 .init = sti_vid_init,
120 .prepare = sti_vid_prepare_layer,
121 .commit = sti_vid_commit_layer,
122 .disable = sti_vid_disable_layer,
123};
124
125struct sti_layer *sti_vid_create(struct device *dev)
126{
127 struct sti_layer *vid;
128
129 vid = devm_kzalloc(dev, sizeof(*vid), GFP_KERNEL);
130 if (!vid) {
131 DRM_ERROR("Failed to allocate memory for VID\n");
132 return NULL;
133 }
134
135 vid->ops = &vid_ops;
136
137 return vid;
138}
diff --git a/drivers/gpu/drm/sti/sti_vid.h b/drivers/gpu/drm/sti/sti_vid.h
new file mode 100644
index 000000000000..2c0aecd63294
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_vid.h
@@ -0,0 +1,12 @@
1/*
2 * Copyright (C) STMicroelectronics SA 2014
3 * Author: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
5 */
6
7#ifndef _STI_VID_H_
8#define _STI_VID_H_
9
10struct sti_layer *sti_vid_create(struct device *dev);
11
12#endif
diff --git a/drivers/gpu/drm/sti/sti_vtac.c b/drivers/gpu/drm/sti/sti_vtac.c
new file mode 100644
index 000000000000..82a51d488434
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_vtac.c
@@ -0,0 +1,215 @@
1/*
2 * Copyright (C) STMicroelectronics SA 2014
3 * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
5 */
6
7#include <linux/clk.h>
8#include <linux/io.h>
9#include <linux/module.h>
10#include <linux/of.h>
11#include <linux/platform_device.h>
12
13#include <drm/drmP.h>
14
15/* registers offset */
16#define VTAC_CONFIG 0x00
17#define VTAC_RX_FIFO_CONFIG 0x04
18#define VTAC_FIFO_CONFIG_VAL 0x04
19
20#define VTAC_SYS_CFG8521 0x824
21#define VTAC_SYS_CFG8522 0x828
22
23/* Number of phyts per pixel */
24#define VTAC_2_5_PPP 0x0005
25#define VTAC_3_PPP 0x0006
26#define VTAC_4_PPP 0x0008
27#define VTAC_5_PPP 0x000A
28#define VTAC_6_PPP 0x000C
29#define VTAC_13_PPP 0x001A
30#define VTAC_14_PPP 0x001C
31#define VTAC_15_PPP 0x001E
32#define VTAC_16_PPP 0x0020
33#define VTAC_17_PPP 0x0022
34#define VTAC_18_PPP 0x0024
35
36/* enable bits */
37#define VTAC_ENABLE 0x3003
38
39#define VTAC_TX_PHY_ENABLE_CLK_PHY BIT(0)
40#define VTAC_TX_PHY_ENABLE_CLK_DLL BIT(1)
41#define VTAC_TX_PHY_PLL_NOT_OSC_MODE BIT(3)
42#define VTAC_TX_PHY_RST_N_DLL_SWITCH BIT(4)
43#define VTAC_TX_PHY_PROG_N3 BIT(9)
44
45
46/**
47 * VTAC mode structure
48 *
49 * @vid_in_width: Video Data Resolution
50 * @phyts_width: Width of phyt buses(phyt low and phyt high).
51 * @phyts_per_pixel: Number of phyts sent per pixel
52 */
53struct sti_vtac_mode {
54 u32 vid_in_width;
55 u32 phyts_width;
56 u32 phyts_per_pixel;
57};
58
59static const struct sti_vtac_mode vtac_mode_main = {0x2, 0x2, VTAC_5_PPP};
60static const struct sti_vtac_mode vtac_mode_aux = {0x1, 0x0, VTAC_17_PPP};
61
62/**
63 * VTAC structure
64 *
65 * @dev: pointer to device structure
66 * @regs: ioremapped registers for RX and TX devices
67 * @phy_regs: phy registers for TX device
68 * @clk: clock
69 * @mode: main or auxillary configuration mode
70 */
71struct sti_vtac {
72 struct device *dev;
73 void __iomem *regs;
74 void __iomem *phy_regs;
75 struct clk *clk;
76 const struct sti_vtac_mode *mode;
77};
78
79static void sti_vtac_rx_set_config(struct sti_vtac *vtac)
80{
81 u32 config;
82
83 /* Enable VTAC clock */
84 if (clk_prepare_enable(vtac->clk))
85 DRM_ERROR("Failed to prepare/enable vtac_rx clock.\n");
86
87 writel(VTAC_FIFO_CONFIG_VAL, vtac->regs + VTAC_RX_FIFO_CONFIG);
88
89 config = VTAC_ENABLE;
90 config |= vtac->mode->vid_in_width << 4;
91 config |= vtac->mode->phyts_width << 16;
92 config |= vtac->mode->phyts_per_pixel << 23;
93 writel(config, vtac->regs + VTAC_CONFIG);
94}
95
96static void sti_vtac_tx_set_config(struct sti_vtac *vtac)
97{
98 u32 phy_config;
99 u32 config;
100
101 /* Enable VTAC clock */
102 if (clk_prepare_enable(vtac->clk))
103 DRM_ERROR("Failed to prepare/enable vtac_tx clock.\n");
104
105 /* Configure vtac phy */
106 phy_config = 0x00000000;
107 writel(phy_config, vtac->phy_regs + VTAC_SYS_CFG8522);
108 phy_config = VTAC_TX_PHY_ENABLE_CLK_PHY;
109 writel(phy_config, vtac->phy_regs + VTAC_SYS_CFG8521);
110 phy_config = readl(vtac->phy_regs + VTAC_SYS_CFG8521);
111 phy_config |= VTAC_TX_PHY_PROG_N3;
112 writel(phy_config, vtac->phy_regs + VTAC_SYS_CFG8521);
113 phy_config = readl(vtac->phy_regs + VTAC_SYS_CFG8521);
114 phy_config |= VTAC_TX_PHY_ENABLE_CLK_DLL;
115 writel(phy_config, vtac->phy_regs + VTAC_SYS_CFG8521);
116 phy_config = readl(vtac->phy_regs + VTAC_SYS_CFG8521);
117 phy_config |= VTAC_TX_PHY_RST_N_DLL_SWITCH;
118 writel(phy_config, vtac->phy_regs + VTAC_SYS_CFG8521);
119 phy_config = readl(vtac->phy_regs + VTAC_SYS_CFG8521);
120 phy_config |= VTAC_TX_PHY_PLL_NOT_OSC_MODE;
121 writel(phy_config, vtac->phy_regs + VTAC_SYS_CFG8521);
122
123 /* Configure vtac tx */
124 config = VTAC_ENABLE;
125 config |= vtac->mode->vid_in_width << 4;
126 config |= vtac->mode->phyts_width << 16;
127 config |= vtac->mode->phyts_per_pixel << 23;
128 writel(config, vtac->regs + VTAC_CONFIG);
129}
130
131static const struct of_device_id vtac_of_match[] = {
132 {
133 .compatible = "st,vtac-main",
134 .data = &vtac_mode_main,
135 }, {
136 .compatible = "st,vtac-aux",
137 .data = &vtac_mode_aux,
138 }, {
139 /* end node */
140 }
141};
142MODULE_DEVICE_TABLE(of, vtac_of_match);
143
144static int sti_vtac_probe(struct platform_device *pdev)
145{
146 struct device *dev = &pdev->dev;
147 struct device_node *np = dev->of_node;
148 const struct of_device_id *id;
149 struct sti_vtac *vtac;
150 struct resource *res;
151
152 vtac = devm_kzalloc(dev, sizeof(*vtac), GFP_KERNEL);
153 if (!vtac)
154 return -ENOMEM;
155
156 vtac->dev = dev;
157
158 id = of_match_node(vtac_of_match, np);
159 if (!id)
160 return -ENOMEM;
161
162 vtac->mode = id->data;
163
164 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
165 if (!res) {
166 DRM_ERROR("Invalid resource\n");
167 return -ENOMEM;
168 }
169 vtac->regs = devm_ioremap_resource(dev, res);
170 if (IS_ERR(vtac->regs))
171 return PTR_ERR(vtac->regs);
172
173
174 vtac->clk = devm_clk_get(dev, "vtac");
175 if (IS_ERR(vtac->clk)) {
176 DRM_ERROR("Cannot get vtac clock\n");
177 return PTR_ERR(vtac->clk);
178 }
179
180 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
181 if (res) {
182 vtac->phy_regs = devm_ioremap_nocache(dev, res->start,
183 resource_size(res));
184 sti_vtac_tx_set_config(vtac);
185 } else {
186
187 sti_vtac_rx_set_config(vtac);
188 }
189
190 platform_set_drvdata(pdev, vtac);
191 DRM_INFO("%s %s\n", __func__, dev_name(vtac->dev));
192
193 return 0;
194}
195
196static int sti_vtac_remove(struct platform_device *pdev)
197{
198 return 0;
199}
200
201struct platform_driver sti_vtac_driver = {
202 .driver = {
203 .name = "sti-vtac",
204 .owner = THIS_MODULE,
205 .of_match_table = vtac_of_match,
206 },
207 .probe = sti_vtac_probe,
208 .remove = sti_vtac_remove,
209};
210
211module_platform_driver(sti_vtac_driver);
212
213MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
214MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
215MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/sti/sti_vtg.c b/drivers/gpu/drm/sti/sti_vtg.c
new file mode 100644
index 000000000000..740d6e347a62
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_vtg.c
@@ -0,0 +1,366 @@
1/*
2 * Copyright (C) STMicroelectronics SA 2014
3 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
4 * Fabien Dessenne <fabien.dessenne@st.com>
5 * Vincent Abriou <vincent.abriou@st.com>
6 * for STMicroelectronics.
7 * License terms: GNU General Public License (GPL), version 2
8 */
9
10#include <linux/module.h>
11#include <linux/notifier.h>
12#include <linux/platform_device.h>
13
14#include <drm/drmP.h>
15
16#include "sti_vtg.h"
17
18#define VTG_TYPE_MASTER 0
19#define VTG_TYPE_SLAVE_BY_EXT0 1
20
21/* registers offset */
22#define VTG_MODE 0x0000
23#define VTG_CLKLN 0x0008
24#define VTG_HLFLN 0x000C
25#define VTG_DRST_AUTOC 0x0010
26#define VTG_VID_TFO 0x0040
27#define VTG_VID_TFS 0x0044
28#define VTG_VID_BFO 0x0048
29#define VTG_VID_BFS 0x004C
30
31#define VTG_HOST_ITS 0x0078
32#define VTG_HOST_ITS_BCLR 0x007C
33#define VTG_HOST_ITM_BCLR 0x0088
34#define VTG_HOST_ITM_BSET 0x008C
35
36#define VTG_H_HD_1 0x00C0
37#define VTG_TOP_V_VD_1 0x00C4
38#define VTG_BOT_V_VD_1 0x00C8
39#define VTG_TOP_V_HD_1 0x00CC
40#define VTG_BOT_V_HD_1 0x00D0
41
42#define VTG_H_HD_2 0x00E0
43#define VTG_TOP_V_VD_2 0x00E4
44#define VTG_BOT_V_VD_2 0x00E8
45#define VTG_TOP_V_HD_2 0x00EC
46#define VTG_BOT_V_HD_2 0x00F0
47
48#define VTG_H_HD_3 0x0100
49#define VTG_TOP_V_VD_3 0x0104
50#define VTG_BOT_V_VD_3 0x0108
51#define VTG_TOP_V_HD_3 0x010C
52#define VTG_BOT_V_HD_3 0x0110
53
54#define VTG_IRQ_BOTTOM BIT(0)
55#define VTG_IRQ_TOP BIT(1)
56#define VTG_IRQ_MASK (VTG_IRQ_TOP | VTG_IRQ_BOTTOM)
57
58/* delay introduced by the Arbitrary Waveform Generator in nb of pixels */
59#define AWG_DELAY_HD (-9)
60#define AWG_DELAY_ED (-8)
61#define AWG_DELAY_SD (-7)
62
63LIST_HEAD(vtg_lookup);
64
65/**
66 * STI VTG structure
67 *
68 * @dev: pointer to device driver
69 * @data: data associated to the device
70 * @irq: VTG irq
71 * @type: VTG type (main or aux)
72 * @notifier_list: notifier callback
73 * @crtc_id: the crtc id for vblank event
74 * @slave: slave vtg
75 * @link: List node to link the structure in lookup list
76 */
77struct sti_vtg {
78 struct device *dev;
79 struct device_node *np;
80 void __iomem *regs;
81 int irq;
82 u32 irq_status;
83 struct raw_notifier_head notifier_list;
84 int crtc_id;
85 struct sti_vtg *slave;
86 struct list_head link;
87};
88
89static void vtg_register(struct sti_vtg *vtg)
90{
91 list_add_tail(&vtg->link, &vtg_lookup);
92}
93
94struct sti_vtg *of_vtg_find(struct device_node *np)
95{
96 struct sti_vtg *vtg;
97
98 list_for_each_entry(vtg, &vtg_lookup, link) {
99 if (vtg->np == np)
100 return vtg;
101 }
102 return NULL;
103}
104EXPORT_SYMBOL(of_vtg_find);
105
106static void vtg_reset(struct sti_vtg *vtg)
107{
108 /* reset slave and then master */
109 if (vtg->slave)
110 vtg_reset(vtg->slave);
111
112 writel(1, vtg->regs + VTG_DRST_AUTOC);
113}
114
115static void vtg_set_mode(struct sti_vtg *vtg,
116 int type, const struct drm_display_mode *mode)
117{
118 u32 tmp;
119
120 if (vtg->slave)
121 vtg_set_mode(vtg->slave, VTG_TYPE_SLAVE_BY_EXT0, mode);
122
123 writel(mode->htotal, vtg->regs + VTG_CLKLN);
124 writel(mode->vtotal * 2, vtg->regs + VTG_HLFLN);
125
126 tmp = (mode->vtotal - mode->vsync_start + 1) << 16;
127 tmp |= mode->htotal - mode->hsync_start;
128 writel(tmp, vtg->regs + VTG_VID_TFO);
129 writel(tmp, vtg->regs + VTG_VID_BFO);
130
131 tmp = (mode->vdisplay + mode->vtotal - mode->vsync_start + 1) << 16;
132 tmp |= mode->hdisplay + mode->htotal - mode->hsync_start;
133 writel(tmp, vtg->regs + VTG_VID_TFS);
134 writel(tmp, vtg->regs + VTG_VID_BFS);
135
136 /* prepare VTG set 1 and 2 for HDMI and VTG set 3 for HD DAC */
137 tmp = (mode->hsync_end - mode->hsync_start) << 16;
138 writel(tmp, vtg->regs + VTG_H_HD_1);
139 writel(tmp, vtg->regs + VTG_H_HD_2);
140
141 tmp = (mode->vsync_end - mode->vsync_start + 1) << 16;
142 tmp |= 1;
143 writel(tmp, vtg->regs + VTG_TOP_V_VD_1);
144 writel(tmp, vtg->regs + VTG_BOT_V_VD_1);
145 writel(0, vtg->regs + VTG_TOP_V_HD_1);
146 writel(0, vtg->regs + VTG_BOT_V_HD_1);
147
148 /* prepare VTG set 2 for for HD DCS */
149 writel(tmp, vtg->regs + VTG_TOP_V_VD_2);
150 writel(tmp, vtg->regs + VTG_BOT_V_VD_2);
151 writel(0, vtg->regs + VTG_TOP_V_HD_2);
152 writel(0, vtg->regs + VTG_BOT_V_HD_2);
153
154 /* prepare VTG set 3 for HD Analog in HD mode */
155 tmp = (mode->hsync_end - mode->hsync_start + AWG_DELAY_HD) << 16;
156 tmp |= mode->htotal + AWG_DELAY_HD;
157 writel(tmp, vtg->regs + VTG_H_HD_3);
158
159 tmp = (mode->vsync_end - mode->vsync_start) << 16;
160 tmp |= mode->vtotal;
161 writel(tmp, vtg->regs + VTG_TOP_V_VD_3);
162 writel(tmp, vtg->regs + VTG_BOT_V_VD_3);
163
164 tmp = (mode->htotal + AWG_DELAY_HD) << 16;
165 tmp |= mode->htotal + AWG_DELAY_HD;
166 writel(tmp, vtg->regs + VTG_TOP_V_HD_3);
167 writel(tmp, vtg->regs + VTG_BOT_V_HD_3);
168
169 /* mode */
170 writel(type, vtg->regs + VTG_MODE);
171}
172
173static void vtg_enable_irq(struct sti_vtg *vtg)
174{
175 /* clear interrupt status and mask */
176 writel(0xFFFF, vtg->regs + VTG_HOST_ITS_BCLR);
177 writel(0xFFFF, vtg->regs + VTG_HOST_ITM_BCLR);
178 writel(VTG_IRQ_MASK, vtg->regs + VTG_HOST_ITM_BSET);
179}
180
181void sti_vtg_set_config(struct sti_vtg *vtg,
182 const struct drm_display_mode *mode)
183{
184 /* write configuration */
185 vtg_set_mode(vtg, VTG_TYPE_MASTER, mode);
186
187 vtg_reset(vtg);
188
189 /* enable irq for the vtg vblank synchro */
190 if (vtg->slave)
191 vtg_enable_irq(vtg->slave);
192 else
193 vtg_enable_irq(vtg);
194}
195EXPORT_SYMBOL(sti_vtg_set_config);
196
197/**
198 * sti_vtg_get_line_number
199 *
200 * @mode: display mode to be used
201 * @y: line
202 *
203 * Return the line number according to the display mode taking
204 * into account the Sync and Back Porch information.
205 * Video frame line numbers start at 1, y starts at 0.
206 * In interlaced modes the start line is the field line number of the odd
207 * field, but y is still defined as a progressive frame.
208 */
209u32 sti_vtg_get_line_number(struct drm_display_mode mode, int y)
210{
211 u32 start_line = mode.vtotal - mode.vsync_start + 1;
212
213 if (mode.flags & DRM_MODE_FLAG_INTERLACE)
214 start_line *= 2;
215
216 return start_line + y;
217}
218EXPORT_SYMBOL(sti_vtg_get_line_number);
219
220/**
221 * sti_vtg_get_pixel_number
222 *
223 * @mode: display mode to be used
224 * @x: row
225 *
226 * Return the pixel number according to the display mode taking
227 * into account the Sync and Back Porch information.
228 * Pixels are counted from 0.
229 */
230u32 sti_vtg_get_pixel_number(struct drm_display_mode mode, int x)
231{
232 return mode.htotal - mode.hsync_start + x;
233}
234EXPORT_SYMBOL(sti_vtg_get_pixel_number);
235
236int sti_vtg_register_client(struct sti_vtg *vtg,
237 struct notifier_block *nb, int crtc_id)
238{
239 if (vtg->slave)
240 return sti_vtg_register_client(vtg->slave, nb, crtc_id);
241
242 vtg->crtc_id = crtc_id;
243 return raw_notifier_chain_register(&vtg->notifier_list, nb);
244}
245EXPORT_SYMBOL(sti_vtg_register_client);
246
247int sti_vtg_unregister_client(struct sti_vtg *vtg, struct notifier_block *nb)
248{
249 if (vtg->slave)
250 return sti_vtg_unregister_client(vtg->slave, nb);
251
252 return raw_notifier_chain_unregister(&vtg->notifier_list, nb);
253}
254EXPORT_SYMBOL(sti_vtg_unregister_client);
255
256static irqreturn_t vtg_irq_thread(int irq, void *arg)
257{
258 struct sti_vtg *vtg = arg;
259 u32 event;
260
261 event = (vtg->irq_status & VTG_IRQ_TOP) ?
262 VTG_TOP_FIELD_EVENT : VTG_BOTTOM_FIELD_EVENT;
263
264 raw_notifier_call_chain(&vtg->notifier_list, event, &vtg->crtc_id);
265
266 return IRQ_HANDLED;
267}
268
269static irqreturn_t vtg_irq(int irq, void *arg)
270{
271 struct sti_vtg *vtg = arg;
272
273 vtg->irq_status = readl(vtg->regs + VTG_HOST_ITS);
274
275 writel(vtg->irq_status, vtg->regs + VTG_HOST_ITS_BCLR);
276
277 /* force sync bus write */
278 readl(vtg->regs + VTG_HOST_ITS);
279
280 return IRQ_WAKE_THREAD;
281}
282
283static int vtg_probe(struct platform_device *pdev)
284{
285 struct device *dev = &pdev->dev;
286 struct device_node *np;
287 struct sti_vtg *vtg;
288 struct resource *res;
289 char irq_name[32];
290 int ret;
291
292 vtg = devm_kzalloc(dev, sizeof(*vtg), GFP_KERNEL);
293 if (!vtg)
294 return -ENOMEM;
295
296 vtg->dev = dev;
297 vtg->np = pdev->dev.of_node;
298
299 /* Get Memory ressources */
300 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
301 if (!res) {
302 DRM_ERROR("Get memory resource failed\n");
303 return -ENOMEM;
304 }
305 vtg->regs = devm_ioremap_nocache(dev, res->start, resource_size(res));
306
307 np = of_parse_phandle(pdev->dev.of_node, "st,slave", 0);
308 if (np) {
309 vtg->slave = of_vtg_find(np);
310
311 if (!vtg->slave)
312 return -EPROBE_DEFER;
313 } else {
314 vtg->irq = platform_get_irq(pdev, 0);
315 if (IS_ERR_VALUE(vtg->irq)) {
316 DRM_ERROR("Failed to get VTG interrupt\n");
317 return vtg->irq;
318 }
319
320 snprintf(irq_name, sizeof(irq_name), "vsync-%s",
321 dev_name(vtg->dev));
322
323 RAW_INIT_NOTIFIER_HEAD(&vtg->notifier_list);
324
325 ret = devm_request_threaded_irq(dev, vtg->irq, vtg_irq,
326 vtg_irq_thread, IRQF_ONESHOT, irq_name, vtg);
327 if (IS_ERR_VALUE(ret)) {
328 DRM_ERROR("Failed to register VTG interrupt\n");
329 return ret;
330 }
331 }
332
333 vtg_register(vtg);
334 platform_set_drvdata(pdev, vtg);
335
336 DRM_INFO("%s %s\n", __func__, dev_name(vtg->dev));
337
338 return 0;
339}
340
341static int vtg_remove(struct platform_device *pdev)
342{
343 return 0;
344}
345
346static const struct of_device_id vtg_of_match[] = {
347 { .compatible = "st,vtg", },
348 { /* sentinel */ }
349};
350MODULE_DEVICE_TABLE(of, vtg_of_match);
351
352struct platform_driver sti_vtg_driver = {
353 .driver = {
354 .name = "sti-vtg",
355 .owner = THIS_MODULE,
356 .of_match_table = vtg_of_match,
357 },
358 .probe = vtg_probe,
359 .remove = vtg_remove,
360};
361
362module_platform_driver(sti_vtg_driver);
363
364MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
365MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
366MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/sti/sti_vtg.h b/drivers/gpu/drm/sti/sti_vtg.h
new file mode 100644
index 000000000000..e84d23f1f57f
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_vtg.h
@@ -0,0 +1,28 @@
1/*
2 * Copyright (C) STMicroelectronics SA 2014
3 * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics.
4 * License terms: GNU General Public License (GPL), version 2
5 */
6
7#ifndef _STI_VTG_H_
8#define _STI_VTG_H_
9
10#define VTG_TOP_FIELD_EVENT 1
11#define VTG_BOTTOM_FIELD_EVENT 2
12
13struct sti_vtg;
14struct drm_display_mode;
15struct notifier_block;
16
17struct sti_vtg *of_vtg_find(struct device_node *np);
18void sti_vtg_set_config(struct sti_vtg *vtg,
19 const struct drm_display_mode *mode);
20int sti_vtg_register_client(struct sti_vtg *vtg,
21 struct notifier_block *nb, int crtc_id);
22int sti_vtg_unregister_client(struct sti_vtg *vtg,
23 struct notifier_block *nb);
24
25u32 sti_vtg_get_line_number(struct drm_display_mode mode, int y);
26u32 sti_vtg_get_pixel_number(struct drm_display_mode mode, int x);
27
28#endif