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 | ||
329 | /** | |
330 | * Configure AWG, writing instructions | |
331 | * | |
332 | * @hda: pointer to HD analog structure | |
333 | * @awg_instr: pointer to AWG instructions table | |
334 | * @nb: nb of AWG instructions | |
335 | */ | |
336 | static void sti_hda_configure_awg(struct sti_hda *hda, u32 *awg_instr, int nb) | |
337 | { | |
338 | unsigned int i; | |
339 | ||
340 | DRM_DEBUG_DRIVER("\n"); | |
341 | ||
342 | for (i = 0; i < nb; i++) | |
343 | hda_write(hda, awg_instr[i], HDA_SYNC_AWGI + i * 4); | |
344 | for (i = nb; i < AWG_MAX_INST; i++) | |
345 | hda_write(hda, 0, HDA_SYNC_AWGI + i * 4); | |
346 | } | |
347 | ||
348 | static void sti_hda_disable(struct drm_bridge *bridge) | |
349 | { | |
350 | struct sti_hda *hda = bridge->driver_private; | |
351 | u32 val; | |
352 | ||
353 | if (!hda->enabled) | |
354 | return; | |
355 | ||
356 | DRM_DEBUG_DRIVER("\n"); | |
357 | ||
358 | /* Disable HD DAC and AWG */ | |
359 | val = hda_read(hda, HDA_ANA_CFG); | |
360 | val &= ~CFG_AWG_ASYNC_EN; | |
361 | hda_write(hda, val, HDA_ANA_CFG); | |
362 | hda_write(hda, 0, HDA_ANA_ANC_CTRL); | |
363 | ||
364 | hda_enable_hd_dacs(hda, false); | |
365 | ||
366 | /* Disable/unprepare hda clock */ | |
367 | clk_disable_unprepare(hda->clk_hddac); | |
368 | clk_disable_unprepare(hda->clk_pix); | |
369 | ||
370 | hda->enabled = false; | |
371 | } | |
372 | ||
373 | static void sti_hda_pre_enable(struct drm_bridge *bridge) | |
374 | { | |
375 | struct sti_hda *hda = bridge->driver_private; | |
376 | u32 val, i, mode_idx; | |
377 | u32 src_filter_y, src_filter_c; | |
378 | u32 *coef_y, *coef_c; | |
379 | u32 filter_mode; | |
380 | ||
381 | DRM_DEBUG_DRIVER("\n"); | |
382 | ||
383 | if (hda->enabled) | |
384 | return; | |
385 | ||
386 | /* Prepare/enable clocks */ | |
387 | if (clk_prepare_enable(hda->clk_pix)) | |
388 | DRM_ERROR("Failed to prepare/enable hda_pix clk\n"); | |
389 | if (clk_prepare_enable(hda->clk_hddac)) | |
390 | DRM_ERROR("Failed to prepare/enable hda_hddac clk\n"); | |
391 | ||
392 | if (!hda_get_mode_idx(hda->mode, &mode_idx)) { | |
393 | DRM_ERROR("Undefined mode\n"); | |
394 | return; | |
395 | } | |
396 | ||
397 | switch (hda_supported_modes[mode_idx].vid_cat) { | |
398 | case VID_HD_148M: | |
399 | DRM_ERROR("Beyond HD analog capabilities\n"); | |
400 | return; | |
401 | case VID_HD_74M: | |
402 | /* HD use alternate 2x filter */ | |
403 | filter_mode = CFG_AWG_FLTR_MODE_HD; | |
404 | src_filter_y = HDA_ANA_SRC_Y_CFG_ALT_2X; | |
405 | src_filter_c = HDA_ANA_SRC_C_CFG_ALT_2X; | |
406 | coef_y = coef_y_alt_2x; | |
407 | coef_c = coef_c_alt_2x; | |
408 | break; | |
409 | case VID_ED: | |
410 | /* ED uses 4x filter */ | |
411 | filter_mode = CFG_AWG_FLTR_MODE_ED; | |
412 | src_filter_y = HDA_ANA_SRC_Y_CFG_4X; | |
413 | src_filter_c = HDA_ANA_SRC_C_CFG_4X; | |
414 | coef_y = coef_yc_4x; | |
415 | coef_c = coef_yc_4x; | |
416 | break; | |
417 | case VID_SD: | |
418 | DRM_ERROR("Not supported\n"); | |
419 | return; | |
420 | default: | |
421 | DRM_ERROR("Undefined resolution\n"); | |
422 | return; | |
423 | } | |
424 | DRM_DEBUG_DRIVER("Using HDA mode #%d\n", mode_idx); | |
425 | ||
426 | /* Enable HD Video DACs */ | |
427 | hda_enable_hd_dacs(hda, true); | |
428 | ||
429 | /* Configure scaler */ | |
430 | hda_write(hda, SCALE_CTRL_Y_DFLT, HDA_ANA_SCALE_CTRL_Y); | |
431 | hda_write(hda, SCALE_CTRL_CB_DFLT, HDA_ANA_SCALE_CTRL_CB); | |
432 | hda_write(hda, SCALE_CTRL_CR_DFLT, HDA_ANA_SCALE_CTRL_CR); | |
433 | ||
434 | /* Configure sampler */ | |
435 | hda_write(hda , src_filter_y, HDA_ANA_SRC_Y_CFG); | |
436 | hda_write(hda, src_filter_c, HDA_ANA_SRC_C_CFG); | |
437 | for (i = 0; i < SAMPLER_COEF_NB; i++) { | |
438 | hda_write(hda, coef_y[i], HDA_COEFF_Y_PH1_TAP123 + i * 4); | |
439 | hda_write(hda, coef_c[i], HDA_COEFF_C_PH1_TAP123 + i * 4); | |
440 | } | |
441 | ||
442 | /* Configure main HDFormatter */ | |
443 | val = 0; | |
444 | val |= (hda->mode.flags & DRM_MODE_FLAG_INTERLACE) ? | |
445 | 0 : CFG_AWG_ASYNC_VSYNC_MTD; | |
446 | val |= (CFG_PBPR_SYNC_OFF_VAL << CFG_PBPR_SYNC_OFF_SHIFT); | |
447 | val |= filter_mode; | |
448 | hda_write(hda, val, HDA_ANA_CFG); | |
449 | ||
450 | /* Configure AWG */ | |
451 | sti_hda_configure_awg(hda, hda_supported_modes[mode_idx].awg_instr, | |
452 | hda_supported_modes[mode_idx].nb_instr); | |
453 | ||
454 | /* Enable AWG */ | |
455 | val = hda_read(hda, HDA_ANA_CFG); | |
456 | val |= CFG_AWG_ASYNC_EN; | |
457 | hda_write(hda, val, HDA_ANA_CFG); | |
458 | ||
459 | hda->enabled = true; | |
460 | } | |
461 | ||
462 | static void sti_hda_set_mode(struct drm_bridge *bridge, | |
463 | struct drm_display_mode *mode, | |
464 | struct drm_display_mode *adjusted_mode) | |
465 | { | |
466 | struct sti_hda *hda = bridge->driver_private; | |
467 | u32 mode_idx; | |
468 | int hddac_rate; | |
469 | int ret; | |
470 | ||
471 | DRM_DEBUG_DRIVER("\n"); | |
472 | ||
473 | memcpy(&hda->mode, mode, sizeof(struct drm_display_mode)); | |
474 | ||
475 | if (!hda_get_mode_idx(hda->mode, &mode_idx)) { | |
476 | DRM_ERROR("Undefined mode\n"); | |
477 | return; | |
478 | } | |
479 | ||
480 | switch (hda_supported_modes[mode_idx].vid_cat) { | |
481 | case VID_HD_74M: | |
482 | /* HD use alternate 2x filter */ | |
483 | hddac_rate = mode->clock * 1000 * 2; | |
484 | break; | |
485 | case VID_ED: | |
486 | /* ED uses 4x filter */ | |
487 | hddac_rate = mode->clock * 1000 * 4; | |
488 | break; | |
489 | default: | |
490 | DRM_ERROR("Undefined mode\n"); | |
491 | return; | |
492 | } | |
493 | ||
494 | /* HD DAC = 148.5Mhz or 108 Mhz */ | |
495 | ret = clk_set_rate(hda->clk_hddac, hddac_rate); | |
496 | if (ret < 0) | |
497 | DRM_ERROR("Cannot set rate (%dHz) for hda_hddac clk\n", | |
498 | hddac_rate); | |
499 | ||
500 | /* HDformatter clock = compositor clock */ | |
501 | ret = clk_set_rate(hda->clk_pix, mode->clock * 1000); | |
502 | if (ret < 0) | |
503 | DRM_ERROR("Cannot set rate (%dHz) for hda_pix clk\n", | |
504 | mode->clock * 1000); | |
505 | } | |
506 | ||
507 | static void sti_hda_bridge_nope(struct drm_bridge *bridge) | |
508 | { | |
509 | /* do nothing */ | |
510 | } | |
511 | ||
c86a5f6e BG |
512 | static const struct drm_bridge_funcs sti_hda_bridge_funcs = { |
513 | .pre_enable = sti_hda_pre_enable, | |
514 | .enable = sti_hda_bridge_nope, | |
515 | .disable = sti_hda_disable, | |
516 | .post_disable = sti_hda_bridge_nope, | |
517 | .mode_set = sti_hda_set_mode, | |
c86a5f6e BG |
518 | }; |
519 | ||
520 | static int sti_hda_connector_get_modes(struct drm_connector *connector) | |
521 | { | |
522 | unsigned int i; | |
523 | int count = 0; | |
524 | struct sti_hda_connector *hda_connector | |
525 | = to_sti_hda_connector(connector); | |
526 | struct sti_hda *hda = hda_connector->hda; | |
527 | ||
528 | DRM_DEBUG_DRIVER("\n"); | |
529 | ||
530 | for (i = 0; i < ARRAY_SIZE(hda_supported_modes); i++) { | |
531 | struct drm_display_mode *mode = | |
532 | drm_mode_duplicate(hda->drm_dev, | |
533 | &hda_supported_modes[i].mode); | |
534 | if (!mode) | |
535 | continue; | |
536 | mode->vrefresh = drm_mode_vrefresh(mode); | |
537 | ||
538 | /* the first mode is the preferred mode */ | |
539 | if (i == 0) | |
540 | mode->type |= DRM_MODE_TYPE_PREFERRED; | |
541 | ||
542 | drm_mode_probed_add(connector, mode); | |
543 | count++; | |
544 | } | |
545 | ||
546 | drm_mode_sort(&connector->modes); | |
547 | ||
548 | return count; | |
549 | } | |
550 | ||
551 | #define CLK_TOLERANCE_HZ 50 | |
552 | ||
553 | static int sti_hda_connector_mode_valid(struct drm_connector *connector, | |
554 | struct drm_display_mode *mode) | |
555 | { | |
556 | int target = mode->clock * 1000; | |
557 | int target_min = target - CLK_TOLERANCE_HZ; | |
558 | int target_max = target + CLK_TOLERANCE_HZ; | |
559 | int result; | |
560 | int idx; | |
561 | struct sti_hda_connector *hda_connector | |
562 | = to_sti_hda_connector(connector); | |
563 | struct sti_hda *hda = hda_connector->hda; | |
564 | ||
565 | if (!hda_get_mode_idx(*mode, &idx)) { | |
566 | return MODE_BAD; | |
567 | } else { | |
568 | result = clk_round_rate(hda->clk_pix, target); | |
569 | ||
570 | DRM_DEBUG_DRIVER("target rate = %d => available rate = %d\n", | |
571 | target, result); | |
572 | ||
573 | if ((result < target_min) || (result > target_max)) { | |
574 | DRM_DEBUG_DRIVER("hda pixclk=%d not supported\n", | |
575 | target); | |
576 | return MODE_BAD; | |
577 | } | |
578 | } | |
579 | ||
580 | return MODE_OK; | |
581 | } | |
582 | ||
583 | struct drm_encoder *sti_hda_best_encoder(struct drm_connector *connector) | |
584 | { | |
585 | struct sti_hda_connector *hda_connector | |
586 | = to_sti_hda_connector(connector); | |
587 | ||
588 | /* Best encoder is the one associated during connector creation */ | |
589 | return hda_connector->encoder; | |
590 | } | |
591 | ||
592 | static struct drm_connector_helper_funcs sti_hda_connector_helper_funcs = { | |
593 | .get_modes = sti_hda_connector_get_modes, | |
594 | .mode_valid = sti_hda_connector_mode_valid, | |
595 | .best_encoder = sti_hda_best_encoder, | |
596 | }; | |
597 | ||
598 | static enum drm_connector_status | |
599 | sti_hda_connector_detect(struct drm_connector *connector, bool force) | |
600 | { | |
601 | return connector_status_connected; | |
602 | } | |
603 | ||
604 | static void sti_hda_connector_destroy(struct drm_connector *connector) | |
605 | { | |
606 | struct sti_hda_connector *hda_connector | |
607 | = to_sti_hda_connector(connector); | |
608 | ||
609 | drm_connector_unregister(connector); | |
610 | drm_connector_cleanup(connector); | |
611 | kfree(hda_connector); | |
612 | } | |
613 | ||
614 | static struct drm_connector_funcs sti_hda_connector_funcs = { | |
de4b00b0 | 615 | .dpms = drm_atomic_helper_connector_dpms, |
c86a5f6e BG |
616 | .fill_modes = drm_helper_probe_single_connector_modes, |
617 | .detect = sti_hda_connector_detect, | |
618 | .destroy = sti_hda_connector_destroy, | |
de4b00b0 BG |
619 | .reset = drm_atomic_helper_connector_reset, |
620 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, | |
621 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | |
c86a5f6e BG |
622 | }; |
623 | ||
624 | static struct drm_encoder *sti_hda_find_encoder(struct drm_device *dev) | |
625 | { | |
626 | struct drm_encoder *encoder; | |
627 | ||
628 | list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { | |
629 | if (encoder->encoder_type == DRM_MODE_ENCODER_DAC) | |
630 | return encoder; | |
631 | } | |
632 | ||
633 | return NULL; | |
634 | } | |
635 | ||
636 | static int sti_hda_bind(struct device *dev, struct device *master, void *data) | |
637 | { | |
638 | struct sti_hda *hda = dev_get_drvdata(dev); | |
639 | struct drm_device *drm_dev = data; | |
640 | struct drm_encoder *encoder; | |
641 | struct sti_hda_connector *connector; | |
642 | struct drm_connector *drm_connector; | |
643 | struct drm_bridge *bridge; | |
644 | int err; | |
645 | ||
646 | /* Set the drm device handle */ | |
647 | hda->drm_dev = drm_dev; | |
648 | ||
649 | encoder = sti_hda_find_encoder(drm_dev); | |
650 | if (!encoder) | |
651 | return -ENOMEM; | |
652 | ||
653 | connector = devm_kzalloc(dev, sizeof(*connector), GFP_KERNEL); | |
654 | if (!connector) | |
655 | return -ENOMEM; | |
656 | ||
657 | connector->hda = hda; | |
658 | ||
659 | bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL); | |
660 | if (!bridge) | |
661 | return -ENOMEM; | |
662 | ||
663 | bridge->driver_private = hda; | |
b07b90fd | 664 | bridge->funcs = &sti_hda_bridge_funcs; |
3d3f8b1f | 665 | drm_bridge_attach(drm_dev, bridge); |
c86a5f6e BG |
666 | |
667 | encoder->bridge = bridge; | |
668 | connector->encoder = encoder; | |
669 | ||
670 | drm_connector = (struct drm_connector *)connector; | |
671 | ||
672 | drm_connector->polled = DRM_CONNECTOR_POLL_HPD; | |
673 | ||
674 | drm_connector_init(drm_dev, drm_connector, | |
675 | &sti_hda_connector_funcs, DRM_MODE_CONNECTOR_Component); | |
676 | drm_connector_helper_add(drm_connector, | |
677 | &sti_hda_connector_helper_funcs); | |
678 | ||
679 | err = drm_connector_register(drm_connector); | |
680 | if (err) | |
681 | goto err_connector; | |
682 | ||
683 | err = drm_mode_connector_attach_encoder(drm_connector, encoder); | |
684 | if (err) { | |
685 | DRM_ERROR("Failed to attach a connector to a encoder\n"); | |
686 | goto err_sysfs; | |
687 | } | |
688 | ||
689 | return 0; | |
690 | ||
691 | err_sysfs: | |
692 | drm_connector_unregister(drm_connector); | |
693 | err_connector: | |
c86a5f6e BG |
694 | drm_connector_cleanup(drm_connector); |
695 | return -EINVAL; | |
696 | } | |
697 | ||
698 | static void sti_hda_unbind(struct device *dev, | |
699 | struct device *master, void *data) | |
700 | { | |
701 | /* do nothing */ | |
702 | } | |
703 | ||
704 | static const struct component_ops sti_hda_ops = { | |
705 | .bind = sti_hda_bind, | |
706 | .unbind = sti_hda_unbind, | |
707 | }; | |
708 | ||
709 | static int sti_hda_probe(struct platform_device *pdev) | |
710 | { | |
711 | struct device *dev = &pdev->dev; | |
712 | struct sti_hda *hda; | |
713 | struct resource *res; | |
714 | ||
715 | DRM_INFO("%s\n", __func__); | |
716 | ||
717 | hda = devm_kzalloc(dev, sizeof(*hda), GFP_KERNEL); | |
718 | if (!hda) | |
719 | return -ENOMEM; | |
720 | ||
721 | hda->dev = pdev->dev; | |
722 | ||
723 | /* Get resources */ | |
724 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hda-reg"); | |
725 | if (!res) { | |
726 | DRM_ERROR("Invalid hda resource\n"); | |
727 | return -ENOMEM; | |
728 | } | |
729 | hda->regs = devm_ioremap_nocache(dev, res->start, resource_size(res)); | |
5024a2b7 WY |
730 | if (!hda->regs) |
731 | return -ENOMEM; | |
c86a5f6e BG |
732 | |
733 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, | |
734 | "video-dacs-ctrl"); | |
735 | if (res) { | |
736 | hda->video_dacs_ctrl = devm_ioremap_nocache(dev, res->start, | |
737 | resource_size(res)); | |
5024a2b7 WY |
738 | if (!hda->video_dacs_ctrl) |
739 | return -ENOMEM; | |
c86a5f6e BG |
740 | } else { |
741 | /* If no existing video-dacs-ctrl resource continue the probe */ | |
742 | DRM_DEBUG_DRIVER("No video-dacs-ctrl resource\n"); | |
743 | hda->video_dacs_ctrl = NULL; | |
744 | } | |
745 | ||
746 | /* Get clock resources */ | |
747 | hda->clk_pix = devm_clk_get(dev, "pix"); | |
748 | if (IS_ERR(hda->clk_pix)) { | |
749 | DRM_ERROR("Cannot get hda_pix clock\n"); | |
750 | return PTR_ERR(hda->clk_pix); | |
751 | } | |
752 | ||
753 | hda->clk_hddac = devm_clk_get(dev, "hddac"); | |
754 | if (IS_ERR(hda->clk_hddac)) { | |
755 | DRM_ERROR("Cannot get hda_hddac clock\n"); | |
756 | return PTR_ERR(hda->clk_hddac); | |
757 | } | |
758 | ||
759 | platform_set_drvdata(pdev, hda); | |
760 | ||
761 | return component_add(&pdev->dev, &sti_hda_ops); | |
762 | } | |
763 | ||
764 | static int sti_hda_remove(struct platform_device *pdev) | |
765 | { | |
766 | component_del(&pdev->dev, &sti_hda_ops); | |
767 | return 0; | |
768 | } | |
769 | ||
8e932cf0 | 770 | static const struct of_device_id hda_of_match[] = { |
c86a5f6e BG |
771 | { .compatible = "st,stih416-hda", }, |
772 | { .compatible = "st,stih407-hda", }, | |
773 | { /* end node */ } | |
774 | }; | |
775 | MODULE_DEVICE_TABLE(of, hda_of_match); | |
776 | ||
777 | struct platform_driver sti_hda_driver = { | |
778 | .driver = { | |
779 | .name = "sti-hda", | |
780 | .owner = THIS_MODULE, | |
781 | .of_match_table = hda_of_match, | |
782 | }, | |
783 | .probe = sti_hda_probe, | |
784 | .remove = sti_hda_remove, | |
785 | }; | |
786 | ||
787 | module_platform_driver(sti_hda_driver); | |
788 | ||
789 | MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>"); | |
790 | MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver"); | |
791 | MODULE_LICENSE("GPL"); |