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