diff options
author | Benjamin Gaignard <benjamin.gaignard@linaro.org> | 2014-07-30 13:25:30 -0400 |
---|---|---|
committer | Benjamin Gaignard <benjamin.gaignard@linaro.org> | 2014-07-30 13:25:30 -0400 |
commit | c86a5f6e1b9c84064231ec867aca281d9e8514a2 (patch) | |
tree | d0075b2403af8322e7100d13ee845e50b25cf14a | |
parent | 5402626c83a2f19da14859e2bab231a53e16ee74 (diff) |
drm: sti: add HDA driver
Add driver to support analog TV ouput.
HDA driver is mapped on drm_bridge and drm_connector structures.
Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
Reviewed-by: Rob Clark <robdclark@gmail.com>
-rw-r--r-- | drivers/gpu/drm/sti/Makefile | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/sti/sti_hda.c | 794 |
2 files changed, 796 insertions, 1 deletions
diff --git a/drivers/gpu/drm/sti/Makefile b/drivers/gpu/drm/sti/Makefile index 12e1a07492f0..4cf0c5561037 100644 --- a/drivers/gpu/drm/sti/Makefile +++ b/drivers/gpu/drm/sti/Makefile | |||
@@ -5,4 +5,5 @@ stihdmi-y := sti_hdmi.o \ | |||
5 | obj-$(CONFIG_DRM_STI) = \ | 5 | obj-$(CONFIG_DRM_STI) = \ |
6 | sti_vtg.o \ | 6 | sti_vtg.o \ |
7 | sti_vtac.o \ | 7 | sti_vtac.o \ |
8 | stihdmi.o \ No newline at end of file | 8 | stihdmi.o \ |
9 | sti_hda.o \ No newline at end of file | ||
diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c new file mode 100644 index 000000000000..72d957f81c05 --- /dev/null +++ b/drivers/gpu/drm/sti/sti_hda.c | |||
@@ -0,0 +1,794 @@ | |||
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"); | ||