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