1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (C) 2016 Broadcom
4*4882a593Smuzhiyun */
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun /**
7*4882a593Smuzhiyun * DOC: VC4 SDTV module
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * The VEC encoder generates PAL or NTSC composite video output.
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun * TV mode selection is done by an atomic property on the encoder,
12*4882a593Smuzhiyun * because a drm_mode_modeinfo is insufficient to distinguish between
13*4882a593Smuzhiyun * PAL and PAL-M or NTSC and NTSC-J.
14*4882a593Smuzhiyun */
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun #include <drm/drm_atomic_helper.h>
17*4882a593Smuzhiyun #include <drm/drm_edid.h>
18*4882a593Smuzhiyun #include <drm/drm_panel.h>
19*4882a593Smuzhiyun #include <drm/drm_probe_helper.h>
20*4882a593Smuzhiyun #include <drm/drm_simple_kms_helper.h>
21*4882a593Smuzhiyun #include <linux/clk.h>
22*4882a593Smuzhiyun #include <linux/component.h>
23*4882a593Smuzhiyun #include <linux/of_graph.h>
24*4882a593Smuzhiyun #include <linux/of_platform.h>
25*4882a593Smuzhiyun #include <linux/pm_runtime.h>
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun #include "vc4_drv.h"
28*4882a593Smuzhiyun #include "vc4_regs.h"
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun /* WSE Registers */
31*4882a593Smuzhiyun #define VEC_WSE_RESET 0xc0
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun #define VEC_WSE_CONTROL 0xc4
34*4882a593Smuzhiyun #define VEC_WSE_WSS_ENABLE BIT(7)
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun #define VEC_WSE_WSS_DATA 0xc8
37*4882a593Smuzhiyun #define VEC_WSE_VPS_DATA1 0xcc
38*4882a593Smuzhiyun #define VEC_WSE_VPS_CONTROL 0xd0
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun /* VEC Registers */
41*4882a593Smuzhiyun #define VEC_REVID 0x100
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun #define VEC_CONFIG0 0x104
44*4882a593Smuzhiyun #define VEC_CONFIG0_YDEL_MASK GENMASK(28, 26)
45*4882a593Smuzhiyun #define VEC_CONFIG0_YDEL(x) ((x) << 26)
46*4882a593Smuzhiyun #define VEC_CONFIG0_CDEL_MASK GENMASK(25, 24)
47*4882a593Smuzhiyun #define VEC_CONFIG0_CDEL(x) ((x) << 24)
48*4882a593Smuzhiyun #define VEC_CONFIG0_PBPR_FIL BIT(18)
49*4882a593Smuzhiyun #define VEC_CONFIG0_CHROMA_GAIN_MASK GENMASK(17, 16)
50*4882a593Smuzhiyun #define VEC_CONFIG0_CHROMA_GAIN_UNITY (0 << 16)
51*4882a593Smuzhiyun #define VEC_CONFIG0_CHROMA_GAIN_1_32 (1 << 16)
52*4882a593Smuzhiyun #define VEC_CONFIG0_CHROMA_GAIN_1_16 (2 << 16)
53*4882a593Smuzhiyun #define VEC_CONFIG0_CHROMA_GAIN_1_8 (3 << 16)
54*4882a593Smuzhiyun #define VEC_CONFIG0_CBURST_GAIN_MASK GENMASK(14, 13)
55*4882a593Smuzhiyun #define VEC_CONFIG0_CBURST_GAIN_UNITY (0 << 13)
56*4882a593Smuzhiyun #define VEC_CONFIG0_CBURST_GAIN_1_128 (1 << 13)
57*4882a593Smuzhiyun #define VEC_CONFIG0_CBURST_GAIN_1_64 (2 << 13)
58*4882a593Smuzhiyun #define VEC_CONFIG0_CBURST_GAIN_1_32 (3 << 13)
59*4882a593Smuzhiyun #define VEC_CONFIG0_CHRBW1 BIT(11)
60*4882a593Smuzhiyun #define VEC_CONFIG0_CHRBW0 BIT(10)
61*4882a593Smuzhiyun #define VEC_CONFIG0_SYNCDIS BIT(9)
62*4882a593Smuzhiyun #define VEC_CONFIG0_BURDIS BIT(8)
63*4882a593Smuzhiyun #define VEC_CONFIG0_CHRDIS BIT(7)
64*4882a593Smuzhiyun #define VEC_CONFIG0_PDEN BIT(6)
65*4882a593Smuzhiyun #define VEC_CONFIG0_YCDELAY BIT(4)
66*4882a593Smuzhiyun #define VEC_CONFIG0_RAMPEN BIT(2)
67*4882a593Smuzhiyun #define VEC_CONFIG0_YCDIS BIT(2)
68*4882a593Smuzhiyun #define VEC_CONFIG0_STD_MASK GENMASK(1, 0)
69*4882a593Smuzhiyun #define VEC_CONFIG0_NTSC_STD 0
70*4882a593Smuzhiyun #define VEC_CONFIG0_PAL_BDGHI_STD 1
71*4882a593Smuzhiyun #define VEC_CONFIG0_PAL_N_STD 3
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun #define VEC_SCHPH 0x108
74*4882a593Smuzhiyun #define VEC_SOFT_RESET 0x10c
75*4882a593Smuzhiyun #define VEC_CLMP0_START 0x144
76*4882a593Smuzhiyun #define VEC_CLMP0_END 0x148
77*4882a593Smuzhiyun #define VEC_FREQ3_2 0x180
78*4882a593Smuzhiyun #define VEC_FREQ1_0 0x184
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun #define VEC_CONFIG1 0x188
81*4882a593Smuzhiyun #define VEC_CONFIG_VEC_RESYNC_OFF BIT(18)
82*4882a593Smuzhiyun #define VEC_CONFIG_RGB219 BIT(17)
83*4882a593Smuzhiyun #define VEC_CONFIG_CBAR_EN BIT(16)
84*4882a593Smuzhiyun #define VEC_CONFIG_TC_OBB BIT(15)
85*4882a593Smuzhiyun #define VEC_CONFIG1_OUTPUT_MODE_MASK GENMASK(12, 10)
86*4882a593Smuzhiyun #define VEC_CONFIG1_C_Y_CVBS (0 << 10)
87*4882a593Smuzhiyun #define VEC_CONFIG1_CVBS_Y_C (1 << 10)
88*4882a593Smuzhiyun #define VEC_CONFIG1_PR_Y_PB (2 << 10)
89*4882a593Smuzhiyun #define VEC_CONFIG1_RGB (4 << 10)
90*4882a593Smuzhiyun #define VEC_CONFIG1_Y_C_CVBS (5 << 10)
91*4882a593Smuzhiyun #define VEC_CONFIG1_C_CVBS_Y (6 << 10)
92*4882a593Smuzhiyun #define VEC_CONFIG1_C_CVBS_CVBS (7 << 10)
93*4882a593Smuzhiyun #define VEC_CONFIG1_DIS_CHR BIT(9)
94*4882a593Smuzhiyun #define VEC_CONFIG1_DIS_LUMA BIT(8)
95*4882a593Smuzhiyun #define VEC_CONFIG1_YCBCR_IN BIT(6)
96*4882a593Smuzhiyun #define VEC_CONFIG1_DITHER_TYPE_LFSR 0
97*4882a593Smuzhiyun #define VEC_CONFIG1_DITHER_TYPE_COUNTER BIT(5)
98*4882a593Smuzhiyun #define VEC_CONFIG1_DITHER_EN BIT(4)
99*4882a593Smuzhiyun #define VEC_CONFIG1_CYDELAY BIT(3)
100*4882a593Smuzhiyun #define VEC_CONFIG1_LUMADIS BIT(2)
101*4882a593Smuzhiyun #define VEC_CONFIG1_COMPDIS BIT(1)
102*4882a593Smuzhiyun #define VEC_CONFIG1_CUSTOM_FREQ BIT(0)
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun #define VEC_CONFIG2 0x18c
105*4882a593Smuzhiyun #define VEC_CONFIG2_PROG_SCAN BIT(15)
106*4882a593Smuzhiyun #define VEC_CONFIG2_SYNC_ADJ_MASK GENMASK(14, 12)
107*4882a593Smuzhiyun #define VEC_CONFIG2_SYNC_ADJ(x) (((x) / 2) << 12)
108*4882a593Smuzhiyun #define VEC_CONFIG2_PBPR_EN BIT(10)
109*4882a593Smuzhiyun #define VEC_CONFIG2_UV_DIG_DIS BIT(6)
110*4882a593Smuzhiyun #define VEC_CONFIG2_RGB_DIG_DIS BIT(5)
111*4882a593Smuzhiyun #define VEC_CONFIG2_TMUX_MASK GENMASK(3, 2)
112*4882a593Smuzhiyun #define VEC_CONFIG2_TMUX_DRIVE0 (0 << 2)
113*4882a593Smuzhiyun #define VEC_CONFIG2_TMUX_RG_COMP (1 << 2)
114*4882a593Smuzhiyun #define VEC_CONFIG2_TMUX_UV_YC (2 << 2)
115*4882a593Smuzhiyun #define VEC_CONFIG2_TMUX_SYNC_YC (3 << 2)
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun #define VEC_INTERRUPT_CONTROL 0x190
118*4882a593Smuzhiyun #define VEC_INTERRUPT_STATUS 0x194
119*4882a593Smuzhiyun #define VEC_FCW_SECAM_B 0x198
120*4882a593Smuzhiyun #define VEC_SECAM_GAIN_VAL 0x19c
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun #define VEC_CONFIG3 0x1a0
123*4882a593Smuzhiyun #define VEC_CONFIG3_HORIZ_LEN_STD (0 << 0)
124*4882a593Smuzhiyun #define VEC_CONFIG3_HORIZ_LEN_MPEG1_SIF (1 << 0)
125*4882a593Smuzhiyun #define VEC_CONFIG3_SHAPE_NON_LINEAR BIT(1)
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun #define VEC_STATUS0 0x200
128*4882a593Smuzhiyun #define VEC_MASK0 0x204
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun #define VEC_CFG 0x208
131*4882a593Smuzhiyun #define VEC_CFG_SG_MODE_MASK GENMASK(6, 5)
132*4882a593Smuzhiyun #define VEC_CFG_SG_MODE(x) ((x) << 5)
133*4882a593Smuzhiyun #define VEC_CFG_SG_EN BIT(4)
134*4882a593Smuzhiyun #define VEC_CFG_VEC_EN BIT(3)
135*4882a593Smuzhiyun #define VEC_CFG_MB_EN BIT(2)
136*4882a593Smuzhiyun #define VEC_CFG_ENABLE BIT(1)
137*4882a593Smuzhiyun #define VEC_CFG_TB_EN BIT(0)
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun #define VEC_DAC_TEST 0x20c
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun #define VEC_DAC_CONFIG 0x210
142*4882a593Smuzhiyun #define VEC_DAC_CONFIG_LDO_BIAS_CTRL(x) ((x) << 24)
143*4882a593Smuzhiyun #define VEC_DAC_CONFIG_DRIVER_CTRL(x) ((x) << 16)
144*4882a593Smuzhiyun #define VEC_DAC_CONFIG_DAC_CTRL(x) (x)
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun #define VEC_DAC_MISC 0x214
147*4882a593Smuzhiyun #define VEC_DAC_MISC_VCD_CTRL_MASK GENMASK(31, 16)
148*4882a593Smuzhiyun #define VEC_DAC_MISC_VCD_CTRL(x) ((x) << 16)
149*4882a593Smuzhiyun #define VEC_DAC_MISC_VID_ACT BIT(8)
150*4882a593Smuzhiyun #define VEC_DAC_MISC_VCD_PWRDN BIT(6)
151*4882a593Smuzhiyun #define VEC_DAC_MISC_BIAS_PWRDN BIT(5)
152*4882a593Smuzhiyun #define VEC_DAC_MISC_DAC_PWRDN BIT(2)
153*4882a593Smuzhiyun #define VEC_DAC_MISC_LDO_PWRDN BIT(1)
154*4882a593Smuzhiyun #define VEC_DAC_MISC_DAC_RST_N BIT(0)
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun /* General VEC hardware state. */
158*4882a593Smuzhiyun struct vc4_vec {
159*4882a593Smuzhiyun struct platform_device *pdev;
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun struct drm_encoder *encoder;
162*4882a593Smuzhiyun struct drm_connector *connector;
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun void __iomem *regs;
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun struct clk *clock;
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun const struct vc4_vec_tv_mode *tv_mode;
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun struct debugfs_regset32 regset;
171*4882a593Smuzhiyun };
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun #define VEC_READ(offset) readl(vec->regs + (offset))
174*4882a593Smuzhiyun #define VEC_WRITE(offset, val) writel(val, vec->regs + (offset))
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun /* VC4 VEC encoder KMS struct */
177*4882a593Smuzhiyun struct vc4_vec_encoder {
178*4882a593Smuzhiyun struct vc4_encoder base;
179*4882a593Smuzhiyun struct vc4_vec *vec;
180*4882a593Smuzhiyun };
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun static inline struct vc4_vec_encoder *
to_vc4_vec_encoder(struct drm_encoder * encoder)183*4882a593Smuzhiyun to_vc4_vec_encoder(struct drm_encoder *encoder)
184*4882a593Smuzhiyun {
185*4882a593Smuzhiyun return container_of(encoder, struct vc4_vec_encoder, base.base);
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun /* VC4 VEC connector KMS struct */
189*4882a593Smuzhiyun struct vc4_vec_connector {
190*4882a593Smuzhiyun struct drm_connector base;
191*4882a593Smuzhiyun struct vc4_vec *vec;
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun /* Since the connector is attached to just the one encoder,
194*4882a593Smuzhiyun * this is the reference to it so we can do the best_encoder()
195*4882a593Smuzhiyun * hook.
196*4882a593Smuzhiyun */
197*4882a593Smuzhiyun struct drm_encoder *encoder;
198*4882a593Smuzhiyun };
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun static inline struct vc4_vec_connector *
to_vc4_vec_connector(struct drm_connector * connector)201*4882a593Smuzhiyun to_vc4_vec_connector(struct drm_connector *connector)
202*4882a593Smuzhiyun {
203*4882a593Smuzhiyun return container_of(connector, struct vc4_vec_connector, base);
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun enum vc4_vec_tv_mode_id {
207*4882a593Smuzhiyun VC4_VEC_TV_MODE_NTSC,
208*4882a593Smuzhiyun VC4_VEC_TV_MODE_NTSC_J,
209*4882a593Smuzhiyun VC4_VEC_TV_MODE_PAL,
210*4882a593Smuzhiyun VC4_VEC_TV_MODE_PAL_M,
211*4882a593Smuzhiyun };
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun struct vc4_vec_tv_mode {
214*4882a593Smuzhiyun const struct drm_display_mode *mode;
215*4882a593Smuzhiyun void (*mode_set)(struct vc4_vec *vec);
216*4882a593Smuzhiyun };
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun static const struct debugfs_reg32 vec_regs[] = {
219*4882a593Smuzhiyun VC4_REG32(VEC_WSE_CONTROL),
220*4882a593Smuzhiyun VC4_REG32(VEC_WSE_WSS_DATA),
221*4882a593Smuzhiyun VC4_REG32(VEC_WSE_VPS_DATA1),
222*4882a593Smuzhiyun VC4_REG32(VEC_WSE_VPS_CONTROL),
223*4882a593Smuzhiyun VC4_REG32(VEC_REVID),
224*4882a593Smuzhiyun VC4_REG32(VEC_CONFIG0),
225*4882a593Smuzhiyun VC4_REG32(VEC_SCHPH),
226*4882a593Smuzhiyun VC4_REG32(VEC_CLMP0_START),
227*4882a593Smuzhiyun VC4_REG32(VEC_CLMP0_END),
228*4882a593Smuzhiyun VC4_REG32(VEC_FREQ3_2),
229*4882a593Smuzhiyun VC4_REG32(VEC_FREQ1_0),
230*4882a593Smuzhiyun VC4_REG32(VEC_CONFIG1),
231*4882a593Smuzhiyun VC4_REG32(VEC_CONFIG2),
232*4882a593Smuzhiyun VC4_REG32(VEC_INTERRUPT_CONTROL),
233*4882a593Smuzhiyun VC4_REG32(VEC_INTERRUPT_STATUS),
234*4882a593Smuzhiyun VC4_REG32(VEC_FCW_SECAM_B),
235*4882a593Smuzhiyun VC4_REG32(VEC_SECAM_GAIN_VAL),
236*4882a593Smuzhiyun VC4_REG32(VEC_CONFIG3),
237*4882a593Smuzhiyun VC4_REG32(VEC_STATUS0),
238*4882a593Smuzhiyun VC4_REG32(VEC_MASK0),
239*4882a593Smuzhiyun VC4_REG32(VEC_CFG),
240*4882a593Smuzhiyun VC4_REG32(VEC_DAC_TEST),
241*4882a593Smuzhiyun VC4_REG32(VEC_DAC_CONFIG),
242*4882a593Smuzhiyun VC4_REG32(VEC_DAC_MISC),
243*4882a593Smuzhiyun };
244*4882a593Smuzhiyun
vc4_vec_ntsc_mode_set(struct vc4_vec * vec)245*4882a593Smuzhiyun static void vc4_vec_ntsc_mode_set(struct vc4_vec *vec)
246*4882a593Smuzhiyun {
247*4882a593Smuzhiyun VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_NTSC_STD | VEC_CONFIG0_PDEN);
248*4882a593Smuzhiyun VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS);
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun
vc4_vec_ntsc_j_mode_set(struct vc4_vec * vec)251*4882a593Smuzhiyun static void vc4_vec_ntsc_j_mode_set(struct vc4_vec *vec)
252*4882a593Smuzhiyun {
253*4882a593Smuzhiyun VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_NTSC_STD);
254*4882a593Smuzhiyun VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS);
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun static const struct drm_display_mode ntsc_mode = {
258*4882a593Smuzhiyun DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 13500,
259*4882a593Smuzhiyun 720, 720 + 14, 720 + 14 + 64, 720 + 14 + 64 + 60, 0,
260*4882a593Smuzhiyun 480, 480 + 7, 480 + 7 + 6, 525, 0,
261*4882a593Smuzhiyun DRM_MODE_FLAG_INTERLACE)
262*4882a593Smuzhiyun };
263*4882a593Smuzhiyun
vc4_vec_pal_mode_set(struct vc4_vec * vec)264*4882a593Smuzhiyun static void vc4_vec_pal_mode_set(struct vc4_vec *vec)
265*4882a593Smuzhiyun {
266*4882a593Smuzhiyun VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_PAL_BDGHI_STD);
267*4882a593Smuzhiyun VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS);
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun
vc4_vec_pal_m_mode_set(struct vc4_vec * vec)270*4882a593Smuzhiyun static void vc4_vec_pal_m_mode_set(struct vc4_vec *vec)
271*4882a593Smuzhiyun {
272*4882a593Smuzhiyun VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_PAL_BDGHI_STD);
273*4882a593Smuzhiyun VEC_WRITE(VEC_CONFIG1,
274*4882a593Smuzhiyun VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ);
275*4882a593Smuzhiyun VEC_WRITE(VEC_FREQ3_2, 0x223b);
276*4882a593Smuzhiyun VEC_WRITE(VEC_FREQ1_0, 0x61d1);
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun static const struct drm_display_mode pal_mode = {
280*4882a593Smuzhiyun DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 13500,
281*4882a593Smuzhiyun 720, 720 + 20, 720 + 20 + 64, 720 + 20 + 64 + 60, 0,
282*4882a593Smuzhiyun 576, 576 + 4, 576 + 4 + 6, 625, 0,
283*4882a593Smuzhiyun DRM_MODE_FLAG_INTERLACE)
284*4882a593Smuzhiyun };
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = {
287*4882a593Smuzhiyun [VC4_VEC_TV_MODE_NTSC] = {
288*4882a593Smuzhiyun .mode = &ntsc_mode,
289*4882a593Smuzhiyun .mode_set = vc4_vec_ntsc_mode_set,
290*4882a593Smuzhiyun },
291*4882a593Smuzhiyun [VC4_VEC_TV_MODE_NTSC_J] = {
292*4882a593Smuzhiyun .mode = &ntsc_mode,
293*4882a593Smuzhiyun .mode_set = vc4_vec_ntsc_j_mode_set,
294*4882a593Smuzhiyun },
295*4882a593Smuzhiyun [VC4_VEC_TV_MODE_PAL] = {
296*4882a593Smuzhiyun .mode = &pal_mode,
297*4882a593Smuzhiyun .mode_set = vc4_vec_pal_mode_set,
298*4882a593Smuzhiyun },
299*4882a593Smuzhiyun [VC4_VEC_TV_MODE_PAL_M] = {
300*4882a593Smuzhiyun .mode = &pal_mode,
301*4882a593Smuzhiyun .mode_set = vc4_vec_pal_m_mode_set,
302*4882a593Smuzhiyun },
303*4882a593Smuzhiyun };
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun static enum drm_connector_status
vc4_vec_connector_detect(struct drm_connector * connector,bool force)306*4882a593Smuzhiyun vc4_vec_connector_detect(struct drm_connector *connector, bool force)
307*4882a593Smuzhiyun {
308*4882a593Smuzhiyun return connector_status_unknown;
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun
vc4_vec_connector_destroy(struct drm_connector * connector)311*4882a593Smuzhiyun static void vc4_vec_connector_destroy(struct drm_connector *connector)
312*4882a593Smuzhiyun {
313*4882a593Smuzhiyun drm_connector_unregister(connector);
314*4882a593Smuzhiyun drm_connector_cleanup(connector);
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun
vc4_vec_connector_get_modes(struct drm_connector * connector)317*4882a593Smuzhiyun static int vc4_vec_connector_get_modes(struct drm_connector *connector)
318*4882a593Smuzhiyun {
319*4882a593Smuzhiyun struct drm_connector_state *state = connector->state;
320*4882a593Smuzhiyun struct drm_display_mode *mode;
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun mode = drm_mode_duplicate(connector->dev,
323*4882a593Smuzhiyun vc4_vec_tv_modes[state->tv.mode].mode);
324*4882a593Smuzhiyun if (!mode) {
325*4882a593Smuzhiyun DRM_ERROR("Failed to create a new display mode\n");
326*4882a593Smuzhiyun return -ENOMEM;
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun drm_mode_probed_add(connector, mode);
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun return 1;
332*4882a593Smuzhiyun }
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun static const struct drm_connector_funcs vc4_vec_connector_funcs = {
335*4882a593Smuzhiyun .detect = vc4_vec_connector_detect,
336*4882a593Smuzhiyun .fill_modes = drm_helper_probe_single_connector_modes,
337*4882a593Smuzhiyun .destroy = vc4_vec_connector_destroy,
338*4882a593Smuzhiyun .reset = drm_atomic_helper_connector_reset,
339*4882a593Smuzhiyun .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
340*4882a593Smuzhiyun .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
341*4882a593Smuzhiyun };
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun static const struct drm_connector_helper_funcs vc4_vec_connector_helper_funcs = {
344*4882a593Smuzhiyun .get_modes = vc4_vec_connector_get_modes,
345*4882a593Smuzhiyun };
346*4882a593Smuzhiyun
vc4_vec_connector_init(struct drm_device * dev,struct vc4_vec * vec)347*4882a593Smuzhiyun static struct drm_connector *vc4_vec_connector_init(struct drm_device *dev,
348*4882a593Smuzhiyun struct vc4_vec *vec)
349*4882a593Smuzhiyun {
350*4882a593Smuzhiyun struct drm_connector *connector = NULL;
351*4882a593Smuzhiyun struct vc4_vec_connector *vec_connector;
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun vec_connector = devm_kzalloc(dev->dev, sizeof(*vec_connector),
354*4882a593Smuzhiyun GFP_KERNEL);
355*4882a593Smuzhiyun if (!vec_connector)
356*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
357*4882a593Smuzhiyun
358*4882a593Smuzhiyun connector = &vec_connector->base;
359*4882a593Smuzhiyun connector->interlace_allowed = true;
360*4882a593Smuzhiyun
361*4882a593Smuzhiyun vec_connector->encoder = vec->encoder;
362*4882a593Smuzhiyun vec_connector->vec = vec;
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun drm_connector_init(dev, connector, &vc4_vec_connector_funcs,
365*4882a593Smuzhiyun DRM_MODE_CONNECTOR_Composite);
366*4882a593Smuzhiyun drm_connector_helper_add(connector, &vc4_vec_connector_helper_funcs);
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun drm_object_attach_property(&connector->base,
369*4882a593Smuzhiyun dev->mode_config.tv_mode_property,
370*4882a593Smuzhiyun VC4_VEC_TV_MODE_NTSC);
371*4882a593Smuzhiyun vec->tv_mode = &vc4_vec_tv_modes[VC4_VEC_TV_MODE_NTSC];
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun drm_connector_attach_encoder(connector, vec->encoder);
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun return connector;
376*4882a593Smuzhiyun }
377*4882a593Smuzhiyun
vc4_vec_encoder_disable(struct drm_encoder * encoder)378*4882a593Smuzhiyun static void vc4_vec_encoder_disable(struct drm_encoder *encoder)
379*4882a593Smuzhiyun {
380*4882a593Smuzhiyun struct vc4_vec_encoder *vc4_vec_encoder = to_vc4_vec_encoder(encoder);
381*4882a593Smuzhiyun struct vc4_vec *vec = vc4_vec_encoder->vec;
382*4882a593Smuzhiyun int ret;
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun VEC_WRITE(VEC_CFG, 0);
385*4882a593Smuzhiyun VEC_WRITE(VEC_DAC_MISC,
386*4882a593Smuzhiyun VEC_DAC_MISC_VCD_PWRDN |
387*4882a593Smuzhiyun VEC_DAC_MISC_BIAS_PWRDN |
388*4882a593Smuzhiyun VEC_DAC_MISC_DAC_PWRDN |
389*4882a593Smuzhiyun VEC_DAC_MISC_LDO_PWRDN);
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun clk_disable_unprepare(vec->clock);
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun ret = pm_runtime_put(&vec->pdev->dev);
394*4882a593Smuzhiyun if (ret < 0) {
395*4882a593Smuzhiyun DRM_ERROR("Failed to release power domain: %d\n", ret);
396*4882a593Smuzhiyun return;
397*4882a593Smuzhiyun }
398*4882a593Smuzhiyun }
399*4882a593Smuzhiyun
vc4_vec_encoder_enable(struct drm_encoder * encoder)400*4882a593Smuzhiyun static void vc4_vec_encoder_enable(struct drm_encoder *encoder)
401*4882a593Smuzhiyun {
402*4882a593Smuzhiyun struct vc4_vec_encoder *vc4_vec_encoder = to_vc4_vec_encoder(encoder);
403*4882a593Smuzhiyun struct vc4_vec *vec = vc4_vec_encoder->vec;
404*4882a593Smuzhiyun int ret;
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun ret = pm_runtime_get_sync(&vec->pdev->dev);
407*4882a593Smuzhiyun if (ret < 0) {
408*4882a593Smuzhiyun DRM_ERROR("Failed to retain power domain: %d\n", ret);
409*4882a593Smuzhiyun return;
410*4882a593Smuzhiyun }
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun /*
413*4882a593Smuzhiyun * We need to set the clock rate each time we enable the encoder
414*4882a593Smuzhiyun * because there's a chance we share the same parent with the HDMI
415*4882a593Smuzhiyun * clock, and both drivers are requesting different rates.
416*4882a593Smuzhiyun * The good news is, these 2 encoders cannot be enabled at the same
417*4882a593Smuzhiyun * time, thus preventing incompatible rate requests.
418*4882a593Smuzhiyun */
419*4882a593Smuzhiyun ret = clk_set_rate(vec->clock, 108000000);
420*4882a593Smuzhiyun if (ret) {
421*4882a593Smuzhiyun DRM_ERROR("Failed to set clock rate: %d\n", ret);
422*4882a593Smuzhiyun return;
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun
425*4882a593Smuzhiyun ret = clk_prepare_enable(vec->clock);
426*4882a593Smuzhiyun if (ret) {
427*4882a593Smuzhiyun DRM_ERROR("Failed to turn on core clock: %d\n", ret);
428*4882a593Smuzhiyun return;
429*4882a593Smuzhiyun }
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun /* Reset the different blocks */
432*4882a593Smuzhiyun VEC_WRITE(VEC_WSE_RESET, 1);
433*4882a593Smuzhiyun VEC_WRITE(VEC_SOFT_RESET, 1);
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun /* Disable the CGSM-A and WSE blocks */
436*4882a593Smuzhiyun VEC_WRITE(VEC_WSE_CONTROL, 0);
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun /* Write config common to all modes. */
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun /*
441*4882a593Smuzhiyun * Color subcarrier phase: phase = 360 * SCHPH / 256.
442*4882a593Smuzhiyun * 0x28 <=> 39.375 deg.
443*4882a593Smuzhiyun */
444*4882a593Smuzhiyun VEC_WRITE(VEC_SCHPH, 0x28);
445*4882a593Smuzhiyun
446*4882a593Smuzhiyun /*
447*4882a593Smuzhiyun * Reset to default values.
448*4882a593Smuzhiyun */
449*4882a593Smuzhiyun VEC_WRITE(VEC_CLMP0_START, 0xac);
450*4882a593Smuzhiyun VEC_WRITE(VEC_CLMP0_END, 0xec);
451*4882a593Smuzhiyun VEC_WRITE(VEC_CONFIG2,
452*4882a593Smuzhiyun VEC_CONFIG2_UV_DIG_DIS | VEC_CONFIG2_RGB_DIG_DIS);
453*4882a593Smuzhiyun VEC_WRITE(VEC_CONFIG3, VEC_CONFIG3_HORIZ_LEN_STD);
454*4882a593Smuzhiyun VEC_WRITE(VEC_DAC_CONFIG,
455*4882a593Smuzhiyun VEC_DAC_CONFIG_DAC_CTRL(0xc) |
456*4882a593Smuzhiyun VEC_DAC_CONFIG_DRIVER_CTRL(0xc) |
457*4882a593Smuzhiyun VEC_DAC_CONFIG_LDO_BIAS_CTRL(0x46));
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun /* Mask all interrupts. */
460*4882a593Smuzhiyun VEC_WRITE(VEC_MASK0, 0);
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun vec->tv_mode->mode_set(vec);
463*4882a593Smuzhiyun
464*4882a593Smuzhiyun VEC_WRITE(VEC_DAC_MISC,
465*4882a593Smuzhiyun VEC_DAC_MISC_VID_ACT | VEC_DAC_MISC_DAC_RST_N);
466*4882a593Smuzhiyun VEC_WRITE(VEC_CFG, VEC_CFG_VEC_EN);
467*4882a593Smuzhiyun }
468*4882a593Smuzhiyun
469*4882a593Smuzhiyun
vc4_vec_encoder_mode_fixup(struct drm_encoder * encoder,const struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)470*4882a593Smuzhiyun static bool vc4_vec_encoder_mode_fixup(struct drm_encoder *encoder,
471*4882a593Smuzhiyun const struct drm_display_mode *mode,
472*4882a593Smuzhiyun struct drm_display_mode *adjusted_mode)
473*4882a593Smuzhiyun {
474*4882a593Smuzhiyun return true;
475*4882a593Smuzhiyun }
476*4882a593Smuzhiyun
vc4_vec_encoder_atomic_mode_set(struct drm_encoder * encoder,struct drm_crtc_state * crtc_state,struct drm_connector_state * conn_state)477*4882a593Smuzhiyun static void vc4_vec_encoder_atomic_mode_set(struct drm_encoder *encoder,
478*4882a593Smuzhiyun struct drm_crtc_state *crtc_state,
479*4882a593Smuzhiyun struct drm_connector_state *conn_state)
480*4882a593Smuzhiyun {
481*4882a593Smuzhiyun struct vc4_vec_encoder *vc4_vec_encoder = to_vc4_vec_encoder(encoder);
482*4882a593Smuzhiyun struct vc4_vec *vec = vc4_vec_encoder->vec;
483*4882a593Smuzhiyun
484*4882a593Smuzhiyun vec->tv_mode = &vc4_vec_tv_modes[conn_state->tv.mode];
485*4882a593Smuzhiyun }
486*4882a593Smuzhiyun
vc4_vec_encoder_atomic_check(struct drm_encoder * encoder,struct drm_crtc_state * crtc_state,struct drm_connector_state * conn_state)487*4882a593Smuzhiyun static int vc4_vec_encoder_atomic_check(struct drm_encoder *encoder,
488*4882a593Smuzhiyun struct drm_crtc_state *crtc_state,
489*4882a593Smuzhiyun struct drm_connector_state *conn_state)
490*4882a593Smuzhiyun {
491*4882a593Smuzhiyun const struct vc4_vec_tv_mode *vec_mode;
492*4882a593Smuzhiyun
493*4882a593Smuzhiyun vec_mode = &vc4_vec_tv_modes[conn_state->tv.mode];
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun if (conn_state->crtc &&
496*4882a593Smuzhiyun !drm_mode_equal(vec_mode->mode, &crtc_state->adjusted_mode))
497*4882a593Smuzhiyun return -EINVAL;
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun return 0;
500*4882a593Smuzhiyun }
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun static const struct drm_encoder_helper_funcs vc4_vec_encoder_helper_funcs = {
503*4882a593Smuzhiyun .disable = vc4_vec_encoder_disable,
504*4882a593Smuzhiyun .enable = vc4_vec_encoder_enable,
505*4882a593Smuzhiyun .mode_fixup = vc4_vec_encoder_mode_fixup,
506*4882a593Smuzhiyun .atomic_check = vc4_vec_encoder_atomic_check,
507*4882a593Smuzhiyun .atomic_mode_set = vc4_vec_encoder_atomic_mode_set,
508*4882a593Smuzhiyun };
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun static const struct of_device_id vc4_vec_dt_match[] = {
511*4882a593Smuzhiyun { .compatible = "brcm,bcm2835-vec", .data = NULL },
512*4882a593Smuzhiyun { /* sentinel */ },
513*4882a593Smuzhiyun };
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun static const char * const tv_mode_names[] = {
516*4882a593Smuzhiyun [VC4_VEC_TV_MODE_NTSC] = "NTSC",
517*4882a593Smuzhiyun [VC4_VEC_TV_MODE_NTSC_J] = "NTSC-J",
518*4882a593Smuzhiyun [VC4_VEC_TV_MODE_PAL] = "PAL",
519*4882a593Smuzhiyun [VC4_VEC_TV_MODE_PAL_M] = "PAL-M",
520*4882a593Smuzhiyun };
521*4882a593Smuzhiyun
vc4_vec_bind(struct device * dev,struct device * master,void * data)522*4882a593Smuzhiyun static int vc4_vec_bind(struct device *dev, struct device *master, void *data)
523*4882a593Smuzhiyun {
524*4882a593Smuzhiyun struct platform_device *pdev = to_platform_device(dev);
525*4882a593Smuzhiyun struct drm_device *drm = dev_get_drvdata(master);
526*4882a593Smuzhiyun struct vc4_dev *vc4 = to_vc4_dev(drm);
527*4882a593Smuzhiyun struct vc4_vec *vec;
528*4882a593Smuzhiyun struct vc4_vec_encoder *vc4_vec_encoder;
529*4882a593Smuzhiyun int ret;
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun ret = drm_mode_create_tv_properties(drm, ARRAY_SIZE(tv_mode_names),
532*4882a593Smuzhiyun tv_mode_names);
533*4882a593Smuzhiyun if (ret)
534*4882a593Smuzhiyun return ret;
535*4882a593Smuzhiyun
536*4882a593Smuzhiyun vec = devm_kzalloc(dev, sizeof(*vec), GFP_KERNEL);
537*4882a593Smuzhiyun if (!vec)
538*4882a593Smuzhiyun return -ENOMEM;
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun vc4_vec_encoder = devm_kzalloc(dev, sizeof(*vc4_vec_encoder),
541*4882a593Smuzhiyun GFP_KERNEL);
542*4882a593Smuzhiyun if (!vc4_vec_encoder)
543*4882a593Smuzhiyun return -ENOMEM;
544*4882a593Smuzhiyun vc4_vec_encoder->base.type = VC4_ENCODER_TYPE_VEC;
545*4882a593Smuzhiyun vc4_vec_encoder->vec = vec;
546*4882a593Smuzhiyun vec->encoder = &vc4_vec_encoder->base.base;
547*4882a593Smuzhiyun
548*4882a593Smuzhiyun vec->pdev = pdev;
549*4882a593Smuzhiyun vec->regs = vc4_ioremap_regs(pdev, 0);
550*4882a593Smuzhiyun if (IS_ERR(vec->regs))
551*4882a593Smuzhiyun return PTR_ERR(vec->regs);
552*4882a593Smuzhiyun vec->regset.base = vec->regs;
553*4882a593Smuzhiyun vec->regset.regs = vec_regs;
554*4882a593Smuzhiyun vec->regset.nregs = ARRAY_SIZE(vec_regs);
555*4882a593Smuzhiyun
556*4882a593Smuzhiyun vec->clock = devm_clk_get(dev, NULL);
557*4882a593Smuzhiyun if (IS_ERR(vec->clock)) {
558*4882a593Smuzhiyun ret = PTR_ERR(vec->clock);
559*4882a593Smuzhiyun if (ret != -EPROBE_DEFER)
560*4882a593Smuzhiyun DRM_ERROR("Failed to get clock: %d\n", ret);
561*4882a593Smuzhiyun return ret;
562*4882a593Smuzhiyun }
563*4882a593Smuzhiyun
564*4882a593Smuzhiyun pm_runtime_enable(dev);
565*4882a593Smuzhiyun
566*4882a593Smuzhiyun drm_simple_encoder_init(drm, vec->encoder, DRM_MODE_ENCODER_TVDAC);
567*4882a593Smuzhiyun drm_encoder_helper_add(vec->encoder, &vc4_vec_encoder_helper_funcs);
568*4882a593Smuzhiyun
569*4882a593Smuzhiyun vec->connector = vc4_vec_connector_init(drm, vec);
570*4882a593Smuzhiyun if (IS_ERR(vec->connector)) {
571*4882a593Smuzhiyun ret = PTR_ERR(vec->connector);
572*4882a593Smuzhiyun goto err_destroy_encoder;
573*4882a593Smuzhiyun }
574*4882a593Smuzhiyun
575*4882a593Smuzhiyun dev_set_drvdata(dev, vec);
576*4882a593Smuzhiyun
577*4882a593Smuzhiyun vc4->vec = vec;
578*4882a593Smuzhiyun
579*4882a593Smuzhiyun vc4_debugfs_add_regset32(drm, "vec_regs", &vec->regset);
580*4882a593Smuzhiyun
581*4882a593Smuzhiyun return 0;
582*4882a593Smuzhiyun
583*4882a593Smuzhiyun err_destroy_encoder:
584*4882a593Smuzhiyun drm_encoder_cleanup(vec->encoder);
585*4882a593Smuzhiyun pm_runtime_disable(dev);
586*4882a593Smuzhiyun
587*4882a593Smuzhiyun return ret;
588*4882a593Smuzhiyun }
589*4882a593Smuzhiyun
vc4_vec_unbind(struct device * dev,struct device * master,void * data)590*4882a593Smuzhiyun static void vc4_vec_unbind(struct device *dev, struct device *master,
591*4882a593Smuzhiyun void *data)
592*4882a593Smuzhiyun {
593*4882a593Smuzhiyun struct drm_device *drm = dev_get_drvdata(master);
594*4882a593Smuzhiyun struct vc4_dev *vc4 = to_vc4_dev(drm);
595*4882a593Smuzhiyun struct vc4_vec *vec = dev_get_drvdata(dev);
596*4882a593Smuzhiyun
597*4882a593Smuzhiyun vc4_vec_connector_destroy(vec->connector);
598*4882a593Smuzhiyun drm_encoder_cleanup(vec->encoder);
599*4882a593Smuzhiyun pm_runtime_disable(dev);
600*4882a593Smuzhiyun
601*4882a593Smuzhiyun vc4->vec = NULL;
602*4882a593Smuzhiyun }
603*4882a593Smuzhiyun
604*4882a593Smuzhiyun static const struct component_ops vc4_vec_ops = {
605*4882a593Smuzhiyun .bind = vc4_vec_bind,
606*4882a593Smuzhiyun .unbind = vc4_vec_unbind,
607*4882a593Smuzhiyun };
608*4882a593Smuzhiyun
vc4_vec_dev_probe(struct platform_device * pdev)609*4882a593Smuzhiyun static int vc4_vec_dev_probe(struct platform_device *pdev)
610*4882a593Smuzhiyun {
611*4882a593Smuzhiyun return component_add(&pdev->dev, &vc4_vec_ops);
612*4882a593Smuzhiyun }
613*4882a593Smuzhiyun
vc4_vec_dev_remove(struct platform_device * pdev)614*4882a593Smuzhiyun static int vc4_vec_dev_remove(struct platform_device *pdev)
615*4882a593Smuzhiyun {
616*4882a593Smuzhiyun component_del(&pdev->dev, &vc4_vec_ops);
617*4882a593Smuzhiyun return 0;
618*4882a593Smuzhiyun }
619*4882a593Smuzhiyun
620*4882a593Smuzhiyun struct platform_driver vc4_vec_driver = {
621*4882a593Smuzhiyun .probe = vc4_vec_dev_probe,
622*4882a593Smuzhiyun .remove = vc4_vec_dev_remove,
623*4882a593Smuzhiyun .driver = {
624*4882a593Smuzhiyun .name = "vc4_vec",
625*4882a593Smuzhiyun .of_match_table = vc4_vec_dt_match,
626*4882a593Smuzhiyun },
627*4882a593Smuzhiyun };
628