Commit | Line | Data |
---|---|---|
c86a5f6e BG |
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> | |
0f3e1561 | 11 | #include <linux/seq_file.h> |
c86a5f6e BG |
12 | |
13 | #include <drm/drmP.h> | |
de4b00b0 | 14 | #include <drm/drm_atomic_helper.h> |
c86a5f6e BG |
15 | #include <drm/drm_crtc_helper.h> |
16 | ||
17 | /* HDformatter registers */ | |
18 | #define HDA_ANA_CFG 0x0000 | |
19 | #define HDA_ANA_SCALE_CTRL_Y 0x0004 | |
20 | #define HDA_ANA_SCALE_CTRL_CB 0x0008 | |
21 | #define HDA_ANA_SCALE_CTRL_CR 0x000C | |
22 | #define HDA_ANA_ANC_CTRL 0x0010 | |
23 | #define HDA_ANA_SRC_Y_CFG 0x0014 | |
24 | #define HDA_COEFF_Y_PH1_TAP123 0x0018 | |
25 | #define HDA_COEFF_Y_PH1_TAP456 0x001C | |
26 | #define HDA_COEFF_Y_PH2_TAP123 0x0020 | |
27 | #define HDA_COEFF_Y_PH2_TAP456 0x0024 | |
28 | #define HDA_COEFF_Y_PH3_TAP123 0x0028 | |
29 | #define HDA_COEFF_Y_PH3_TAP456 0x002C | |
30 | #define HDA_COEFF_Y_PH4_TAP123 0x0030 | |
31 | #define HDA_COEFF_Y_PH4_TAP456 0x0034 | |
32 | #define HDA_ANA_SRC_C_CFG 0x0040 | |
33 | #define HDA_COEFF_C_PH1_TAP123 0x0044 | |
34 | #define HDA_COEFF_C_PH1_TAP456 0x0048 | |
35 | #define HDA_COEFF_C_PH2_TAP123 0x004C | |
36 | #define HDA_COEFF_C_PH2_TAP456 0x0050 | |
37 | #define HDA_COEFF_C_PH3_TAP123 0x0054 | |
38 | #define HDA_COEFF_C_PH3_TAP456 0x0058 | |
39 | #define HDA_COEFF_C_PH4_TAP123 0x005C | |
40 | #define HDA_COEFF_C_PH4_TAP456 0x0060 | |
41 | #define HDA_SYNC_AWGI 0x0300 | |
42 | ||
43 | /* HDA_ANA_CFG */ | |
44 | #define CFG_AWG_ASYNC_EN BIT(0) | |
45 | #define CFG_AWG_ASYNC_HSYNC_MTD BIT(1) | |
46 | #define CFG_AWG_ASYNC_VSYNC_MTD BIT(2) | |
47 | #define CFG_AWG_SYNC_DEL BIT(3) | |
48 | #define CFG_AWG_FLTR_MODE_SHIFT 4 | |
49 | #define CFG_AWG_FLTR_MODE_MASK (0xF << CFG_AWG_FLTR_MODE_SHIFT) | |
50 | #define CFG_AWG_FLTR_MODE_SD (0 << CFG_AWG_FLTR_MODE_SHIFT) | |
51 | #define CFG_AWG_FLTR_MODE_ED (1 << CFG_AWG_FLTR_MODE_SHIFT) | |
52 | #define CFG_AWG_FLTR_MODE_HD (2 << CFG_AWG_FLTR_MODE_SHIFT) | |
53 | #define CFG_SYNC_ON_PBPR_MASK BIT(8) | |
54 | #define CFG_PREFILTER_EN_MASK BIT(9) | |
55 | #define CFG_PBPR_SYNC_OFF_SHIFT 16 | |
56 | #define CFG_PBPR_SYNC_OFF_MASK (0x7FF << CFG_PBPR_SYNC_OFF_SHIFT) | |
57 | #define CFG_PBPR_SYNC_OFF_VAL 0x117 /* Voltage dependent. stiH416 */ | |
58 | ||
59 | /* Default scaling values */ | |
60 | #define SCALE_CTRL_Y_DFLT 0x00C50256 | |
61 | #define SCALE_CTRL_CB_DFLT 0x00DB0249 | |
62 | #define SCALE_CTRL_CR_DFLT 0x00DB0249 | |
63 | ||
64 | /* Video DACs control */ | |
65 | #define VIDEO_DACS_CONTROL_MASK 0x0FFF | |
66 | #define VIDEO_DACS_CONTROL_SYSCFG2535 0x085C /* for stih416 */ | |
67 | #define DAC_CFG_HD_OFF_SHIFT 5 | |
68 | #define DAC_CFG_HD_OFF_MASK (0x7 << DAC_CFG_HD_OFF_SHIFT) | |
69 | #define VIDEO_DACS_CONTROL_SYSCFG5072 0x0120 /* for stih407 */ | |
70 | #define DAC_CFG_HD_HZUVW_OFF_MASK BIT(1) | |
71 | ||
72 | ||
73 | /* Upsampler values for the alternative 2X Filter */ | |
74 | #define SAMPLER_COEF_NB 8 | |
75 | #define HDA_ANA_SRC_Y_CFG_ALT_2X 0x01130000 | |
76 | static u32 coef_y_alt_2x[] = { | |
77 | 0x00FE83FB, 0x1F900401, 0x00000000, 0x00000000, | |
78 | 0x00F408F9, 0x055F7C25, 0x00000000, 0x00000000 | |
79 | }; | |
80 | ||
81 | #define HDA_ANA_SRC_C_CFG_ALT_2X 0x01750004 | |
82 | static u32 coef_c_alt_2x[] = { | |
83 | 0x001305F7, 0x05274BD0, 0x00000000, 0x00000000, | |
84 | 0x0004907C, 0x09C80B9D, 0x00000000, 0x00000000 | |
85 | }; | |
86 | ||
87 | /* Upsampler values for the 4X Filter */ | |
88 | #define HDA_ANA_SRC_Y_CFG_4X 0x01ED0005 | |
89 | #define HDA_ANA_SRC_C_CFG_4X 0x01ED0004 | |
90 | static u32 coef_yc_4x[] = { | |
91 | 0x00FC827F, 0x008FE20B, 0x00F684FC, 0x050F7C24, | |
92 | 0x00F4857C, 0x0A1F402E, 0x00FA027F, 0x0E076E1D | |
93 | }; | |
94 | ||
95 | /* AWG instructions for some video modes */ | |
96 | #define AWG_MAX_INST 64 | |
97 | ||
98 | /* 720p@50 */ | |
99 | static u32 AWGi_720p_50[] = { | |
100 | 0x00000971, 0x00000C26, 0x0000013B, 0x00000CDA, | |
101 | 0x00000104, 0x00000E7E, 0x00000E7F, 0x0000013B, | |
102 | 0x00000D8E, 0x00000104, 0x00001804, 0x00000971, | |
103 | 0x00000C26, 0x0000003B, 0x00000FB4, 0x00000FB5, | |
104 | 0x00000104, 0x00001AE8 | |
105 | }; | |
106 | ||
107 | #define NN_720p_50 ARRAY_SIZE(AWGi_720p_50) | |
108 | ||
109 | /* 720p@60 */ | |
110 | static u32 AWGi_720p_60[] = { | |
111 | 0x00000971, 0x00000C26, 0x0000013B, 0x00000CDA, | |
112 | 0x00000104, 0x00000E7E, 0x00000E7F, 0x0000013B, | |
113 | 0x00000C44, 0x00000104, 0x00001804, 0x00000971, | |
114 | 0x00000C26, 0x0000003B, 0x00000F0F, 0x00000F10, | |
115 | 0x00000104, 0x00001AE8 | |
116 | }; | |
117 | ||
118 | #define NN_720p_60 ARRAY_SIZE(AWGi_720p_60) | |
119 | ||
120 | /* 1080p@30 */ | |
121 | static u32 AWGi_1080p_30[] = { | |
122 | 0x00000971, 0x00000C2A, 0x0000013B, 0x00000C56, | |
123 | 0x00000104, 0x00000FDC, 0x00000FDD, 0x0000013B, | |
124 | 0x00000C2A, 0x00000104, 0x00001804, 0x00000971, | |
125 | 0x00000C2A, 0x0000003B, 0x00000EBE, 0x00000EBF, | |
126 | 0x00000EBF, 0x00000104, 0x00001A2F, 0x00001C4B, | |
127 | 0x00001C52 | |
128 | }; | |
129 | ||
130 | #define NN_1080p_30 ARRAY_SIZE(AWGi_1080p_30) | |
131 | ||
132 | /* 1080p@25 */ | |
133 | static u32 AWGi_1080p_25[] = { | |
134 | 0x00000971, 0x00000C2A, 0x0000013B, 0x00000C56, | |
135 | 0x00000104, 0x00000FDC, 0x00000FDD, 0x0000013B, | |
136 | 0x00000DE2, 0x00000104, 0x00001804, 0x00000971, | |
137 | 0x00000C2A, 0x0000003B, 0x00000F51, 0x00000F51, | |
138 | 0x00000F52, 0x00000104, 0x00001A2F, 0x00001C4B, | |
139 | 0x00001C52 | |
140 | }; | |
141 | ||
142 | #define NN_1080p_25 ARRAY_SIZE(AWGi_1080p_25) | |
143 | ||
144 | /* 1080p@24 */ | |
145 | static u32 AWGi_1080p_24[] = { | |
146 | 0x00000971, 0x00000C2A, 0x0000013B, 0x00000C56, | |
147 | 0x00000104, 0x00000FDC, 0x00000FDD, 0x0000013B, | |
148 | 0x00000E50, 0x00000104, 0x00001804, 0x00000971, | |
149 | 0x00000C2A, 0x0000003B, 0x00000F76, 0x00000F76, | |
150 | 0x00000F76, 0x00000104, 0x00001A2F, 0x00001C4B, | |
151 | 0x00001C52 | |
152 | }; | |
153 | ||
154 | #define NN_1080p_24 ARRAY_SIZE(AWGi_1080p_24) | |
155 | ||
156 | /* 720x480p@60 */ | |
157 | static u32 AWGi_720x480p_60[] = { | |
158 | 0x00000904, 0x00000F18, 0x0000013B, 0x00001805, | |
159 | 0x00000904, 0x00000C3D, 0x0000003B, 0x00001A06 | |
160 | }; | |
161 | ||
162 | #define NN_720x480p_60 ARRAY_SIZE(AWGi_720x480p_60) | |
163 | ||
164 | /* Video mode category */ | |
165 | enum sti_hda_vid_cat { | |
166 | VID_SD, | |
167 | VID_ED, | |
168 | VID_HD_74M, | |
169 | VID_HD_148M | |
170 | }; | |
171 | ||
172 | struct sti_hda_video_config { | |
173 | struct drm_display_mode mode; | |
174 | u32 *awg_instr; | |
175 | int nb_instr; | |
176 | enum sti_hda_vid_cat vid_cat; | |
177 | }; | |
178 | ||
179 | /* HD analog supported modes | |
180 | * Interlaced modes may be added when supported by the whole display chain | |
181 | */ | |
182 | static const struct sti_hda_video_config hda_supported_modes[] = { | |
183 | /* 1080p30 74.250Mhz */ | |
184 | {{DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008, | |
185 | 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, | |
186 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC)}, | |
187 | AWGi_1080p_30, NN_1080p_30, VID_HD_74M}, | |
188 | /* 1080p30 74.176Mhz */ | |
189 | {{DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74176, 1920, 2008, | |
190 | 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, | |
191 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC)}, | |
192 | AWGi_1080p_30, NN_1080p_30, VID_HD_74M}, | |
193 | /* 1080p24 74.250Mhz */ | |
194 | {{DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2558, | |
195 | 2602, 2750, 0, 1080, 1084, 1089, 1125, 0, | |
196 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC)}, | |
197 | AWGi_1080p_24, NN_1080p_24, VID_HD_74M}, | |
198 | /* 1080p24 74.176Mhz */ | |
199 | {{DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74176, 1920, 2558, | |
200 | 2602, 2750, 0, 1080, 1084, 1089, 1125, 0, | |
201 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC)}, | |
202 | AWGi_1080p_24, NN_1080p_24, VID_HD_74M}, | |
203 | /* 1080p25 74.250Mhz */ | |
204 | {{DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448, | |
205 | 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, | |
206 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC)}, | |
207 | AWGi_1080p_25, NN_1080p_25, VID_HD_74M}, | |
208 | /* 720p60 74.250Mhz */ | |
209 | {{DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1390, | |
210 | 1430, 1650, 0, 720, 725, 730, 750, 0, | |
211 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC)}, | |
212 | AWGi_720p_60, NN_720p_60, VID_HD_74M}, | |
213 | /* 720p60 74.176Mhz */ | |
214 | {{DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74176, 1280, 1390, | |
215 | 1430, 1650, 0, 720, 725, 730, 750, 0, | |
216 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC)}, | |
217 | AWGi_720p_60, NN_720p_60, VID_HD_74M}, | |
218 | /* 720p50 74.250Mhz */ | |
219 | {{DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1720, | |
220 | 1760, 1980, 0, 720, 725, 730, 750, 0, | |
221 | DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC)}, | |
222 | AWGi_720p_50, NN_720p_50, VID_HD_74M}, | |
223 | /* 720x480p60 27.027Mhz */ | |
224 | {{DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27027, 720, 736, | |
225 | 798, 858, 0, 480, 489, 495, 525, 0, | |
226 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC)}, | |
227 | AWGi_720x480p_60, NN_720x480p_60, VID_ED}, | |
228 | /* 720x480p60 27.000Mhz */ | |
229 | {{DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736, | |
230 | 798, 858, 0, 480, 489, 495, 525, 0, | |
231 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC)}, | |
232 | AWGi_720x480p_60, NN_720x480p_60, VID_ED} | |
233 | }; | |
234 | ||
235 | /** | |
236 | * STI hd analog structure | |
237 | * | |
238 | * @dev: driver device | |
239 | * @drm_dev: pointer to drm device | |
240 | * @mode: current display mode selected | |
241 | * @regs: HD analog register | |
242 | * @video_dacs_ctrl: video DACS control register | |
243 | * @enabled: true if HD analog is enabled else false | |
244 | */ | |
245 | struct sti_hda { | |
246 | struct device dev; | |
247 | struct drm_device *drm_dev; | |
248 | struct drm_display_mode mode; | |
249 | void __iomem *regs; | |
250 | void __iomem *video_dacs_ctrl; | |
251 | struct clk *clk_pix; | |
252 | struct clk *clk_hddac; | |
253 | bool enabled; | |
254 | }; | |
255 | ||
256 | struct sti_hda_connector { | |
257 | struct drm_connector drm_connector; | |
258 | struct drm_encoder *encoder; | |
259 | struct sti_hda *hda; | |
260 | }; | |
261 | ||
262 | #define to_sti_hda_connector(x) \ | |
263 | container_of(x, struct sti_hda_connector, drm_connector) | |
264 | ||
265 | static u32 hda_read(struct sti_hda *hda, int offset) | |
266 | { | |
267 | return readl(hda->regs + offset); | |
268 | } | |
269 | ||
270 | static void hda_write(struct sti_hda *hda, u32 val, int offset) | |
271 | { | |
272 | writel(val, hda->regs + offset); | |
273 | } | |
274 | ||
275 | /** | |
276 | * Search for a video mode in the supported modes table | |
277 | * | |
278 | * @mode: mode being searched | |
279 | * @idx: index of the found mode | |
280 | * | |
281 | * Return true if mode is found | |
282 | */ | |
283 | static bool hda_get_mode_idx(struct drm_display_mode mode, int *idx) | |
284 | { | |
285 | unsigned int i; | |
286 | ||
287 | for (i = 0; i < ARRAY_SIZE(hda_supported_modes); i++) | |
288 | if (drm_mode_equal(&hda_supported_modes[i].mode, &mode)) { | |
289 | *idx = i; | |
290 | return true; | |
291 | } | |
292 | return false; | |
293 | } | |
294 | ||
295 | /** | |
296 | * Enable the HD DACS | |
297 | * | |
298 | * @hda: pointer to HD analog structure | |
299 | * @enable: true if HD DACS need to be enabled, else false | |
300 | */ | |
301 | static void hda_enable_hd_dacs(struct sti_hda *hda, bool enable) | |
302 | { | |
303 | u32 mask; | |
304 | ||
305 | if (hda->video_dacs_ctrl) { | |
306 | u32 val; | |
307 | ||
308 | switch ((u32)hda->video_dacs_ctrl & VIDEO_DACS_CONTROL_MASK) { | |
309 | case VIDEO_DACS_CONTROL_SYSCFG2535: | |
310 | mask = DAC_CFG_HD_OFF_MASK; | |
311 | break; | |
312 | case VIDEO_DACS_CONTROL_SYSCFG5072: | |
313 | mask = DAC_CFG_HD_HZUVW_OFF_MASK; | |
314 | break; | |
315 | default: | |
316 | DRM_INFO("Video DACS control register not supported!"); | |
317 | return; | |
318 | } | |
319 | ||
320 | val = readl(hda->video_dacs_ctrl); | |
321 | if (enable) | |
322 | val &= ~mask; | |
323 | else | |
324 | val |= mask; | |
325 | ||
326 | writel(val, hda->video_dacs_ctrl); | |
327 | } | |
328 | } | |
329 | ||
6c84578c VA |
330 | #define DBGFS_DUMP(reg) seq_printf(s, "\n %-25s 0x%08X", #reg, \ |
331 | readl(hda->regs + reg)) | |
332 | ||
333 | static void hda_dbg_cfg(struct seq_file *s, int val) | |
334 | { | |
335 | seq_puts(s, "\tAWG "); | |
336 | seq_puts(s, val & CFG_AWG_ASYNC_EN ? "enabled" : "disabled"); | |
337 | } | |
338 | ||
339 | static void hda_dbg_awg_microcode(struct seq_file *s, void __iomem *reg) | |
340 | { | |
341 | unsigned int i; | |
342 | ||
343 | seq_puts(s, "\n\n"); | |
344 | seq_puts(s, " HDA AWG microcode:"); | |
345 | for (i = 0; i < AWG_MAX_INST; i++) { | |
346 | if (i % 8 == 0) | |
347 | seq_printf(s, "\n %04X:", i); | |
348 | seq_printf(s, " %04X", readl(reg + i * 4)); | |
349 | } | |
350 | } | |
351 | ||
352 | static void hda_dbg_video_dacs_ctrl(struct seq_file *s, void __iomem *reg) | |
353 | { | |
354 | u32 val = readl(reg); | |
355 | u32 mask; | |
356 | ||
357 | switch ((u32)reg & VIDEO_DACS_CONTROL_MASK) { | |
358 | case VIDEO_DACS_CONTROL_SYSCFG2535: | |
359 | mask = DAC_CFG_HD_OFF_MASK; | |
360 | break; | |
361 | case VIDEO_DACS_CONTROL_SYSCFG5072: | |
362 | mask = DAC_CFG_HD_HZUVW_OFF_MASK; | |
363 | break; | |
364 | default: | |
365 | DRM_DEBUG_DRIVER("Warning: DACS ctrl register not supported!"); | |
366 | return; | |
367 | } | |
368 | ||
369 | seq_puts(s, "\n"); | |
370 | seq_printf(s, "\n %-25s 0x%08X", "VIDEO_DACS_CONTROL", val); | |
371 | seq_puts(s, "\tHD DACs "); | |
372 | seq_puts(s, val & mask ? "disabled" : "enabled"); | |
373 | } | |
374 | ||
375 | static int hda_dbg_show(struct seq_file *s, void *data) | |
376 | { | |
377 | struct drm_info_node *node = s->private; | |
378 | struct sti_hda *hda = (struct sti_hda *)node->info_ent->data; | |
6c84578c VA |
379 | |
380 | seq_printf(s, "HD Analog: (vaddr = 0x%p)", hda->regs); | |
381 | DBGFS_DUMP(HDA_ANA_CFG); | |
382 | hda_dbg_cfg(s, readl(hda->regs + HDA_ANA_CFG)); | |
383 | DBGFS_DUMP(HDA_ANA_SCALE_CTRL_Y); | |
384 | DBGFS_DUMP(HDA_ANA_SCALE_CTRL_CB); | |
385 | DBGFS_DUMP(HDA_ANA_SCALE_CTRL_CR); | |
386 | DBGFS_DUMP(HDA_ANA_ANC_CTRL); | |
387 | DBGFS_DUMP(HDA_ANA_SRC_Y_CFG); | |
388 | DBGFS_DUMP(HDA_ANA_SRC_C_CFG); | |
389 | hda_dbg_awg_microcode(s, hda->regs + HDA_SYNC_AWGI); | |
390 | if (hda->video_dacs_ctrl) | |
391 | hda_dbg_video_dacs_ctrl(s, hda->video_dacs_ctrl); | |
392 | seq_puts(s, "\n"); | |
393 | ||
6c84578c VA |
394 | return 0; |
395 | } | |
396 | ||
397 | static struct drm_info_list hda_debugfs_files[] = { | |
398 | { "hda", hda_dbg_show, 0, NULL }, | |
399 | }; | |
400 | ||
401 | static void hda_debugfs_exit(struct sti_hda *hda, struct drm_minor *minor) | |
402 | { | |
403 | drm_debugfs_remove_files(hda_debugfs_files, | |
404 | ARRAY_SIZE(hda_debugfs_files), | |
405 | minor); | |
406 | } | |
407 | ||
408 | static int hda_debugfs_init(struct sti_hda *hda, struct drm_minor *minor) | |
409 | { | |
410 | unsigned int i; | |
411 | ||
412 | for (i = 0; i < ARRAY_SIZE(hda_debugfs_files); i++) | |
413 | hda_debugfs_files[i].data = hda; | |
414 | ||
415 | return drm_debugfs_create_files(hda_debugfs_files, | |
416 | ARRAY_SIZE(hda_debugfs_files), | |
417 | minor->debugfs_root, minor); | |
418 | } | |
419 | ||
c86a5f6e BG |
420 | /** |
421 | * Configure AWG, writing instructions | |
422 | * | |
423 | * @hda: pointer to HD analog structure | |
424 | * @awg_instr: pointer to AWG instructions table | |
425 | * @nb: nb of AWG instructions | |
426 | */ | |
427 | static void sti_hda_configure_awg(struct sti_hda *hda, u32 *awg_instr, int nb) | |
428 | { | |
429 | unsigned int i; | |
430 | ||
431 | DRM_DEBUG_DRIVER("\n"); | |
432 | ||
433 | for (i = 0; i < nb; i++) | |
434 | hda_write(hda, awg_instr[i], HDA_SYNC_AWGI + i * 4); | |
435 | for (i = nb; i < AWG_MAX_INST; i++) | |
436 | hda_write(hda, 0, HDA_SYNC_AWGI + i * 4); | |
437 | } | |
438 | ||
439 | static void sti_hda_disable(struct drm_bridge *bridge) | |
440 | { | |
441 | struct sti_hda *hda = bridge->driver_private; | |
442 | u32 val; | |
443 | ||
444 | if (!hda->enabled) | |
445 | return; | |
446 | ||
447 | DRM_DEBUG_DRIVER("\n"); | |
448 | ||
449 | /* Disable HD DAC and AWG */ | |
450 | val = hda_read(hda, HDA_ANA_CFG); | |
451 | val &= ~CFG_AWG_ASYNC_EN; | |
452 | hda_write(hda, val, HDA_ANA_CFG); | |
453 | hda_write(hda, 0, HDA_ANA_ANC_CTRL); | |
454 | ||
455 | hda_enable_hd_dacs(hda, false); | |
456 | ||
457 | /* Disable/unprepare hda clock */ | |
458 | clk_disable_unprepare(hda->clk_hddac); | |
459 | clk_disable_unprepare(hda->clk_pix); | |
460 | ||
461 | hda->enabled = false; | |
462 | } | |
463 | ||
464 | static void sti_hda_pre_enable(struct drm_bridge *bridge) | |
465 | { | |
466 | struct sti_hda *hda = bridge->driver_private; | |
467 | u32 val, i, mode_idx; | |
468 | u32 src_filter_y, src_filter_c; | |
469 | u32 *coef_y, *coef_c; | |
470 | u32 filter_mode; | |
471 | ||
472 | DRM_DEBUG_DRIVER("\n"); | |
473 | ||
474 | if (hda->enabled) | |
475 | return; | |
476 | ||
477 | /* Prepare/enable clocks */ | |
478 | if (clk_prepare_enable(hda->clk_pix)) | |
479 | DRM_ERROR("Failed to prepare/enable hda_pix clk\n"); | |
480 | if (clk_prepare_enable(hda->clk_hddac)) | |
481 | DRM_ERROR("Failed to prepare/enable hda_hddac clk\n"); | |
482 | ||
483 | if (!hda_get_mode_idx(hda->mode, &mode_idx)) { | |
484 | DRM_ERROR("Undefined mode\n"); | |
485 | return; | |
486 | } | |
487 | ||
488 | switch (hda_supported_modes[mode_idx].vid_cat) { | |
489 | case VID_HD_148M: | |
490 | DRM_ERROR("Beyond HD analog capabilities\n"); | |
491 | return; | |
492 | case VID_HD_74M: | |
493 | /* HD use alternate 2x filter */ | |
494 | filter_mode = CFG_AWG_FLTR_MODE_HD; | |
495 | src_filter_y = HDA_ANA_SRC_Y_CFG_ALT_2X; | |
496 | src_filter_c = HDA_ANA_SRC_C_CFG_ALT_2X; | |
497 | coef_y = coef_y_alt_2x; | |
498 | coef_c = coef_c_alt_2x; | |
499 | break; | |
500 | case VID_ED: | |
501 | /* ED uses 4x filter */ | |
502 | filter_mode = CFG_AWG_FLTR_MODE_ED; | |
503 | src_filter_y = HDA_ANA_SRC_Y_CFG_4X; | |
504 | src_filter_c = HDA_ANA_SRC_C_CFG_4X; | |
505 | coef_y = coef_yc_4x; | |
506 | coef_c = coef_yc_4x; | |
507 | break; | |
508 | case VID_SD: | |
509 | DRM_ERROR("Not supported\n"); | |
510 | return; | |
511 | default: | |
512 | DRM_ERROR("Undefined resolution\n"); | |
513 | return; | |
514 | } | |
515 | DRM_DEBUG_DRIVER("Using HDA mode #%d\n", mode_idx); | |
516 | ||
517 | /* Enable HD Video DACs */ | |
518 | hda_enable_hd_dacs(hda, true); | |
519 | ||
520 | /* Configure scaler */ | |
521 | hda_write(hda, SCALE_CTRL_Y_DFLT, HDA_ANA_SCALE_CTRL_Y); | |
522 | hda_write(hda, SCALE_CTRL_CB_DFLT, HDA_ANA_SCALE_CTRL_CB); | |
523 | hda_write(hda, SCALE_CTRL_CR_DFLT, HDA_ANA_SCALE_CTRL_CR); | |
524 | ||
525 | /* Configure sampler */ | |
526 | hda_write(hda , src_filter_y, HDA_ANA_SRC_Y_CFG); | |
527 | hda_write(hda, src_filter_c, HDA_ANA_SRC_C_CFG); | |
528 | for (i = 0; i < SAMPLER_COEF_NB; i++) { | |
529 | hda_write(hda, coef_y[i], HDA_COEFF_Y_PH1_TAP123 + i * 4); | |
530 | hda_write(hda, coef_c[i], HDA_COEFF_C_PH1_TAP123 + i * 4); | |
531 | } | |
532 | ||
533 | /* Configure main HDFormatter */ | |
534 | val = 0; | |
535 | val |= (hda->mode.flags & DRM_MODE_FLAG_INTERLACE) ? | |
536 | 0 : CFG_AWG_ASYNC_VSYNC_MTD; | |
537 | val |= (CFG_PBPR_SYNC_OFF_VAL << CFG_PBPR_SYNC_OFF_SHIFT); | |
538 | val |= filter_mode; | |
539 | hda_write(hda, val, HDA_ANA_CFG); | |
540 | ||
541 | /* Configure AWG */ | |
542 | sti_hda_configure_awg(hda, hda_supported_modes[mode_idx].awg_instr, | |
543 | hda_supported_modes[mode_idx].nb_instr); | |
544 | ||
545 | /* Enable AWG */ | |
546 | val = hda_read(hda, HDA_ANA_CFG); | |
547 | val |= CFG_AWG_ASYNC_EN; | |
548 | hda_write(hda, val, HDA_ANA_CFG); | |
549 | ||
550 | hda->enabled = true; | |
551 | } | |
552 | ||
553 | static void sti_hda_set_mode(struct drm_bridge *bridge, | |
554 | struct drm_display_mode *mode, | |
555 | struct drm_display_mode *adjusted_mode) | |
556 | { | |
557 | struct sti_hda *hda = bridge->driver_private; | |
558 | u32 mode_idx; | |
559 | int hddac_rate; | |
560 | int ret; | |
561 | ||
562 | DRM_DEBUG_DRIVER("\n"); | |
563 | ||
564 | memcpy(&hda->mode, mode, sizeof(struct drm_display_mode)); | |
565 | ||
566 | if (!hda_get_mode_idx(hda->mode, &mode_idx)) { | |
567 | DRM_ERROR("Undefined mode\n"); | |
568 | return; | |
569 | } | |
570 | ||
571 | switch (hda_supported_modes[mode_idx].vid_cat) { | |
572 | case VID_HD_74M: | |
573 | /* HD use alternate 2x filter */ | |
574 | hddac_rate = mode->clock * 1000 * 2; | |
575 | break; | |
576 | case VID_ED: | |
577 | /* ED uses 4x filter */ | |
578 | hddac_rate = mode->clock * 1000 * 4; | |
579 | break; | |
580 | default: | |
581 | DRM_ERROR("Undefined mode\n"); | |
582 | return; | |
583 | } | |
584 | ||
585 | /* HD DAC = 148.5Mhz or 108 Mhz */ | |
586 | ret = clk_set_rate(hda->clk_hddac, hddac_rate); | |
587 | if (ret < 0) | |
588 | DRM_ERROR("Cannot set rate (%dHz) for hda_hddac clk\n", | |
589 | hddac_rate); | |
590 | ||
591 | /* HDformatter clock = compositor clock */ | |
592 | ret = clk_set_rate(hda->clk_pix, mode->clock * 1000); | |
593 | if (ret < 0) | |
594 | DRM_ERROR("Cannot set rate (%dHz) for hda_pix clk\n", | |
595 | mode->clock * 1000); | |
596 | } | |
597 | ||
598 | static void sti_hda_bridge_nope(struct drm_bridge *bridge) | |
599 | { | |
600 | /* do nothing */ | |
601 | } | |
602 | ||
c86a5f6e BG |
603 | static const struct drm_bridge_funcs sti_hda_bridge_funcs = { |
604 | .pre_enable = sti_hda_pre_enable, | |
605 | .enable = sti_hda_bridge_nope, | |
606 | .disable = sti_hda_disable, | |
607 | .post_disable = sti_hda_bridge_nope, | |
608 | .mode_set = sti_hda_set_mode, | |
c86a5f6e BG |
609 | }; |
610 | ||
611 | static int sti_hda_connector_get_modes(struct drm_connector *connector) | |
612 | { | |
613 | unsigned int i; | |
614 | int count = 0; | |
615 | struct sti_hda_connector *hda_connector | |
616 | = to_sti_hda_connector(connector); | |
617 | struct sti_hda *hda = hda_connector->hda; | |
618 | ||
619 | DRM_DEBUG_DRIVER("\n"); | |
620 | ||
621 | for (i = 0; i < ARRAY_SIZE(hda_supported_modes); i++) { | |
622 | struct drm_display_mode *mode = | |
623 | drm_mode_duplicate(hda->drm_dev, | |
624 | &hda_supported_modes[i].mode); | |
625 | if (!mode) | |
626 | continue; | |
627 | mode->vrefresh = drm_mode_vrefresh(mode); | |
628 | ||
629 | /* the first mode is the preferred mode */ | |
630 | if (i == 0) | |
631 | mode->type |= DRM_MODE_TYPE_PREFERRED; | |
632 | ||
633 | drm_mode_probed_add(connector, mode); | |
634 | count++; | |
635 | } | |
636 | ||
c86a5f6e BG |
637 | return count; |
638 | } | |
639 | ||
640 | #define CLK_TOLERANCE_HZ 50 | |
641 | ||
642 | static int sti_hda_connector_mode_valid(struct drm_connector *connector, | |
643 | struct drm_display_mode *mode) | |
644 | { | |
645 | int target = mode->clock * 1000; | |
646 | int target_min = target - CLK_TOLERANCE_HZ; | |
647 | int target_max = target + CLK_TOLERANCE_HZ; | |
648 | int result; | |
649 | int idx; | |
650 | struct sti_hda_connector *hda_connector | |
651 | = to_sti_hda_connector(connector); | |
652 | struct sti_hda *hda = hda_connector->hda; | |
653 | ||
654 | if (!hda_get_mode_idx(*mode, &idx)) { | |
655 | return MODE_BAD; | |
656 | } else { | |
657 | result = clk_round_rate(hda->clk_pix, target); | |
658 | ||
659 | DRM_DEBUG_DRIVER("target rate = %d => available rate = %d\n", | |
660 | target, result); | |
661 | ||
662 | if ((result < target_min) || (result > target_max)) { | |
663 | DRM_DEBUG_DRIVER("hda pixclk=%d not supported\n", | |
664 | target); | |
665 | return MODE_BAD; | |
666 | } | |
667 | } | |
668 | ||
669 | return MODE_OK; | |
670 | } | |
671 | ||
c5de4853 VS |
672 | static const |
673 | struct drm_connector_helper_funcs sti_hda_connector_helper_funcs = { | |
c86a5f6e BG |
674 | .get_modes = sti_hda_connector_get_modes, |
675 | .mode_valid = sti_hda_connector_mode_valid, | |
c86a5f6e BG |
676 | }; |
677 | ||
678 | static enum drm_connector_status | |
679 | sti_hda_connector_detect(struct drm_connector *connector, bool force) | |
680 | { | |
681 | return connector_status_connected; | |
682 | } | |
683 | ||
83af0a48 | 684 | static int sti_hda_late_register(struct drm_connector *connector) |
c86a5f6e BG |
685 | { |
686 | struct sti_hda_connector *hda_connector | |
687 | = to_sti_hda_connector(connector); | |
83af0a48 BG |
688 | struct sti_hda *hda = hda_connector->hda; |
689 | ||
690 | if (hda_debugfs_init(hda, hda->drm_dev->primary)) { | |
691 | DRM_ERROR("HDA debugfs setup failed\n"); | |
692 | return -EINVAL; | |
693 | } | |
c86a5f6e | 694 | |
83af0a48 | 695 | return 0; |
c86a5f6e BG |
696 | } |
697 | ||
c5de4853 | 698 | static const struct drm_connector_funcs sti_hda_connector_funcs = { |
de4b00b0 | 699 | .dpms = drm_atomic_helper_connector_dpms, |
c86a5f6e BG |
700 | .fill_modes = drm_helper_probe_single_connector_modes, |
701 | .detect = sti_hda_connector_detect, | |
83af0a48 | 702 | .destroy = drm_connector_cleanup, |
de4b00b0 BG |
703 | .reset = drm_atomic_helper_connector_reset, |
704 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, | |
705 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | |
83af0a48 | 706 | .late_register = sti_hda_late_register, |
c86a5f6e BG |
707 | }; |
708 | ||
709 | static struct drm_encoder *sti_hda_find_encoder(struct drm_device *dev) | |
710 | { | |
711 | struct drm_encoder *encoder; | |
712 | ||
713 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { | |
714 | if (encoder->encoder_type == DRM_MODE_ENCODER_DAC) | |
715 | return encoder; | |
716 | } | |
717 | ||
718 | return NULL; | |
719 | } | |
720 | ||
721 | static int sti_hda_bind(struct device *dev, struct device *master, void *data) | |
722 | { | |
723 | struct sti_hda *hda = dev_get_drvdata(dev); | |
724 | struct drm_device *drm_dev = data; | |
725 | struct drm_encoder *encoder; | |
726 | struct sti_hda_connector *connector; | |
727 | struct drm_connector *drm_connector; | |
728 | struct drm_bridge *bridge; | |
729 | int err; | |
730 | ||
731 | /* Set the drm device handle */ | |
732 | hda->drm_dev = drm_dev; | |
733 | ||
734 | encoder = sti_hda_find_encoder(drm_dev); | |
735 | if (!encoder) | |
736 | return -ENOMEM; | |
737 | ||
738 | connector = devm_kzalloc(dev, sizeof(*connector), GFP_KERNEL); | |
739 | if (!connector) | |
740 | return -ENOMEM; | |
741 | ||
742 | connector->hda = hda; | |
743 | ||
744 | bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL); | |
745 | if (!bridge) | |
746 | return -ENOMEM; | |
747 | ||
748 | bridge->driver_private = hda; | |
b07b90fd | 749 | bridge->funcs = &sti_hda_bridge_funcs; |
3d3f8b1f | 750 | drm_bridge_attach(drm_dev, bridge); |
c86a5f6e BG |
751 | |
752 | encoder->bridge = bridge; | |
753 | connector->encoder = encoder; | |
754 | ||
755 | drm_connector = (struct drm_connector *)connector; | |
756 | ||
757 | drm_connector->polled = DRM_CONNECTOR_POLL_HPD; | |
758 | ||
759 | drm_connector_init(drm_dev, drm_connector, | |
760 | &sti_hda_connector_funcs, DRM_MODE_CONNECTOR_Component); | |
761 | drm_connector_helper_add(drm_connector, | |
762 | &sti_hda_connector_helper_funcs); | |
763 | ||
c86a5f6e BG |
764 | err = drm_mode_connector_attach_encoder(drm_connector, encoder); |
765 | if (err) { | |
766 | DRM_ERROR("Failed to attach a connector to a encoder\n"); | |
767 | goto err_sysfs; | |
768 | } | |
769 | ||
9b60514d VA |
770 | /* force to disable hd dacs at startup */ |
771 | hda_enable_hd_dacs(hda, false); | |
772 | ||
c86a5f6e BG |
773 | return 0; |
774 | ||
775 | err_sysfs: | |
84601dbd | 776 | drm_bridge_remove(bridge); |
c86a5f6e BG |
777 | return -EINVAL; |
778 | } | |
779 | ||
780 | static void sti_hda_unbind(struct device *dev, | |
781 | struct device *master, void *data) | |
782 | { | |
6c84578c VA |
783 | struct sti_hda *hda = dev_get_drvdata(dev); |
784 | struct drm_device *drm_dev = data; | |
785 | ||
786 | hda_debugfs_exit(hda, drm_dev->primary); | |
c86a5f6e BG |
787 | } |
788 | ||
789 | static const struct component_ops sti_hda_ops = { | |
790 | .bind = sti_hda_bind, | |
791 | .unbind = sti_hda_unbind, | |
792 | }; | |
793 | ||
794 | static int sti_hda_probe(struct platform_device *pdev) | |
795 | { | |
796 | struct device *dev = &pdev->dev; | |
797 | struct sti_hda *hda; | |
798 | struct resource *res; | |
799 | ||
800 | DRM_INFO("%s\n", __func__); | |
801 | ||
802 | hda = devm_kzalloc(dev, sizeof(*hda), GFP_KERNEL); | |
803 | if (!hda) | |
804 | return -ENOMEM; | |
805 | ||
806 | hda->dev = pdev->dev; | |
807 | ||
808 | /* Get resources */ | |
809 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hda-reg"); | |
810 | if (!res) { | |
811 | DRM_ERROR("Invalid hda resource\n"); | |
812 | return -ENOMEM; | |
813 | } | |
814 | hda->regs = devm_ioremap_nocache(dev, res->start, resource_size(res)); | |
5024a2b7 WY |
815 | if (!hda->regs) |
816 | return -ENOMEM; | |
c86a5f6e BG |
817 | |
818 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, | |
819 | "video-dacs-ctrl"); | |
820 | if (res) { | |
821 | hda->video_dacs_ctrl = devm_ioremap_nocache(dev, res->start, | |
822 | resource_size(res)); | |
5024a2b7 WY |
823 | if (!hda->video_dacs_ctrl) |
824 | return -ENOMEM; | |
c86a5f6e BG |
825 | } else { |
826 | /* If no existing video-dacs-ctrl resource continue the probe */ | |
827 | DRM_DEBUG_DRIVER("No video-dacs-ctrl resource\n"); | |
828 | hda->video_dacs_ctrl = NULL; | |
829 | } | |
830 | ||
831 | /* Get clock resources */ | |
832 | hda->clk_pix = devm_clk_get(dev, "pix"); | |
833 | if (IS_ERR(hda->clk_pix)) { | |
834 | DRM_ERROR("Cannot get hda_pix clock\n"); | |
835 | return PTR_ERR(hda->clk_pix); | |
836 | } | |
837 | ||
838 | hda->clk_hddac = devm_clk_get(dev, "hddac"); | |
839 | if (IS_ERR(hda->clk_hddac)) { | |
840 | DRM_ERROR("Cannot get hda_hddac clock\n"); | |
841 | return PTR_ERR(hda->clk_hddac); | |
842 | } | |
843 | ||
844 | platform_set_drvdata(pdev, hda); | |
845 | ||
846 | return component_add(&pdev->dev, &sti_hda_ops); | |
847 | } | |
848 | ||
849 | static int sti_hda_remove(struct platform_device *pdev) | |
850 | { | |
851 | component_del(&pdev->dev, &sti_hda_ops); | |
852 | return 0; | |
853 | } | |
854 | ||
8e932cf0 | 855 | static const struct of_device_id hda_of_match[] = { |
c86a5f6e BG |
856 | { .compatible = "st,stih416-hda", }, |
857 | { .compatible = "st,stih407-hda", }, | |
858 | { /* end node */ } | |
859 | }; | |
860 | MODULE_DEVICE_TABLE(of, hda_of_match); | |
861 | ||
862 | struct platform_driver sti_hda_driver = { | |
863 | .driver = { | |
864 | .name = "sti-hda", | |
865 | .owner = THIS_MODULE, | |
866 | .of_match_table = hda_of_match, | |
867 | }, | |
868 | .probe = sti_hda_probe, | |
869 | .remove = sti_hda_remove, | |
870 | }; | |
871 | ||
c86a5f6e BG |
872 | MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>"); |
873 | MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver"); | |
874 | MODULE_LICENSE("GPL"); |