2 * Copyright 2017 Linaro Ltd.
3 * Copyright 2017 ZTE Corporation.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
11 #include <linux/clk.h>
12 #include <linux/component.h>
13 #include <linux/mfd/syscon.h>
14 #include <linux/regmap.h>
16 #include <drm/drm_atomic_helper.h>
17 #include <drm/drm_probe_helper.h>
20 #include "zx_drm_drv.h"
21 #include "zx_tvenc_regs.h"
24 struct zx_tvenc_pwrctrl
{
25 struct regmap
*regmap
;
31 struct drm_connector connector
;
32 struct drm_encoder encoder
;
35 const struct vou_inf
*inf
;
36 struct zx_tvenc_pwrctrl pwrctrl
;
39 #define to_zx_tvenc(x) container_of(x, struct zx_tvenc, x)
41 struct zx_tvenc_mode
{
42 struct drm_display_mode mode
;
51 u32 line_timing_param
;
53 u32 blank_black_level
;
56 u32 sub_carrier_phase1
;
57 u32 phase_line_incr_cvbs
;
61 * The CRM cannot directly provide a suitable frequency, and we have to
62 * ask a multiplied rate from CRM and use the divider in VOU to get the
65 #define TVENC_CLOCK_MULTIPLIER 4
67 static const struct zx_tvenc_mode tvenc_mode_pal
= {
69 .clock
= 13500 * TVENC_CLOCK_MULTIPLIER
,
71 .hsync_start
= 720 + 12,
72 .hsync_end
= 720 + 12 + 2,
73 .htotal
= 720 + 12 + 2 + 130,
75 .vsync_start
= 576 + 2,
76 .vsync_end
= 576 + 2 + 2,
77 .vtotal
= 576 + 2 + 2 + 20,
78 .flags
= DRM_MODE_FLAG_NHSYNC
| DRM_MODE_FLAG_NVSYNC
|
79 DRM_MODE_FLAG_INTERLACE
,
81 .video_info
= 0x00040040,
82 .video_res
= 0x05a9c760,
83 .field1_param
= 0x0004d416,
84 .field2_param
= 0x0009b94f,
85 .burst_line_odd1
= 0x0004d406,
86 .burst_line_even1
= 0x0009b53e,
87 .burst_line_odd2
= 0x0004d805,
88 .burst_line_even2
= 0x0009b93f,
89 .line_timing_param
= 0x06a96fdf,
90 .weight_value
= 0x00c188a0,
91 .blank_black_level
= 0x0000fcfc,
92 .burst_level
= 0x00001595,
93 .control_param
= 0x00000001,
94 .sub_carrier_phase1
= 0x1504c566,
95 .phase_line_incr_cvbs
= 0xc068db8c,
98 static const struct zx_tvenc_mode tvenc_mode_ntsc
= {
100 .clock
= 13500 * TVENC_CLOCK_MULTIPLIER
,
102 .hsync_start
= 720 + 16,
103 .hsync_end
= 720 + 16 + 2,
104 .htotal
= 720 + 16 + 2 + 120,
106 .vsync_start
= 480 + 3,
107 .vsync_end
= 480 + 3 + 2,
108 .vtotal
= 480 + 3 + 2 + 17,
109 .flags
= DRM_MODE_FLAG_NHSYNC
| DRM_MODE_FLAG_NVSYNC
|
110 DRM_MODE_FLAG_INTERLACE
,
112 .video_info
= 0x00040080,
113 .video_res
= 0x05a8375a,
114 .field1_param
= 0x00041817,
115 .field2_param
= 0x0008351e,
116 .burst_line_odd1
= 0x00041006,
117 .burst_line_even1
= 0x0008290d,
118 .burst_line_odd2
= 0x00000000,
119 .burst_line_even2
= 0x00000000,
120 .line_timing_param
= 0x06a8ef9e,
121 .weight_value
= 0x00b68197,
122 .blank_black_level
= 0x0000f0f0,
123 .burst_level
= 0x0000009c,
124 .control_param
= 0x00000001,
125 .sub_carrier_phase1
= 0x10f83e10,
126 .phase_line_incr_cvbs
= 0x80000000,
129 static const struct zx_tvenc_mode
*tvenc_modes
[] = {
134 static const struct zx_tvenc_mode
*
135 zx_tvenc_find_zmode(struct drm_display_mode
*mode
)
139 for (i
= 0; i
< ARRAY_SIZE(tvenc_modes
); i
++) {
140 const struct zx_tvenc_mode
*zmode
= tvenc_modes
[i
];
142 if (drm_mode_equal(mode
, &zmode
->mode
))
149 static void zx_tvenc_encoder_mode_set(struct drm_encoder
*encoder
,
150 struct drm_display_mode
*mode
,
151 struct drm_display_mode
*adj_mode
)
153 struct zx_tvenc
*tvenc
= to_zx_tvenc(encoder
);
154 const struct zx_tvenc_mode
*zmode
;
155 struct vou_div_config configs
[] = {
156 { VOU_DIV_INF
, VOU_DIV_4
},
157 { VOU_DIV_TVENC
, VOU_DIV_1
},
158 { VOU_DIV_LAYER
, VOU_DIV_2
},
161 zx_vou_config_dividers(encoder
->crtc
, configs
, ARRAY_SIZE(configs
));
163 zmode
= zx_tvenc_find_zmode(mode
);
165 DRM_DEV_ERROR(tvenc
->dev
, "failed to find zmode\n");
169 zx_writel(tvenc
->mmio
+ VENC_VIDEO_INFO
, zmode
->video_info
);
170 zx_writel(tvenc
->mmio
+ VENC_VIDEO_RES
, zmode
->video_res
);
171 zx_writel(tvenc
->mmio
+ VENC_FIELD1_PARAM
, zmode
->field1_param
);
172 zx_writel(tvenc
->mmio
+ VENC_FIELD2_PARAM
, zmode
->field2_param
);
173 zx_writel(tvenc
->mmio
+ VENC_LINE_O_1
, zmode
->burst_line_odd1
);
174 zx_writel(tvenc
->mmio
+ VENC_LINE_E_1
, zmode
->burst_line_even1
);
175 zx_writel(tvenc
->mmio
+ VENC_LINE_O_2
, zmode
->burst_line_odd2
);
176 zx_writel(tvenc
->mmio
+ VENC_LINE_E_2
, zmode
->burst_line_even2
);
177 zx_writel(tvenc
->mmio
+ VENC_LINE_TIMING_PARAM
,
178 zmode
->line_timing_param
);
179 zx_writel(tvenc
->mmio
+ VENC_WEIGHT_VALUE
, zmode
->weight_value
);
180 zx_writel(tvenc
->mmio
+ VENC_BLANK_BLACK_LEVEL
,
181 zmode
->blank_black_level
);
182 zx_writel(tvenc
->mmio
+ VENC_BURST_LEVEL
, zmode
->burst_level
);
183 zx_writel(tvenc
->mmio
+ VENC_CONTROL_PARAM
, zmode
->control_param
);
184 zx_writel(tvenc
->mmio
+ VENC_SUB_CARRIER_PHASE1
,
185 zmode
->sub_carrier_phase1
);
186 zx_writel(tvenc
->mmio
+ VENC_PHASE_LINE_INCR_CVBS
,
187 zmode
->phase_line_incr_cvbs
);
190 static void zx_tvenc_encoder_enable(struct drm_encoder
*encoder
)
192 struct zx_tvenc
*tvenc
= to_zx_tvenc(encoder
);
193 struct zx_tvenc_pwrctrl
*pwrctrl
= &tvenc
->pwrctrl
;
195 /* Set bit to power up TVENC DAC */
196 regmap_update_bits(pwrctrl
->regmap
, pwrctrl
->reg
, pwrctrl
->mask
,
199 vou_inf_enable(VOU_TV_ENC
, encoder
->crtc
);
201 zx_writel(tvenc
->mmio
+ VENC_ENABLE
, 1);
204 static void zx_tvenc_encoder_disable(struct drm_encoder
*encoder
)
206 struct zx_tvenc
*tvenc
= to_zx_tvenc(encoder
);
207 struct zx_tvenc_pwrctrl
*pwrctrl
= &tvenc
->pwrctrl
;
209 zx_writel(tvenc
->mmio
+ VENC_ENABLE
, 0);
211 vou_inf_disable(VOU_TV_ENC
, encoder
->crtc
);
213 /* Clear bit to power down TVENC DAC */
214 regmap_update_bits(pwrctrl
->regmap
, pwrctrl
->reg
, pwrctrl
->mask
, 0);
217 static const struct drm_encoder_helper_funcs zx_tvenc_encoder_helper_funcs
= {
218 .enable
= zx_tvenc_encoder_enable
,
219 .disable
= zx_tvenc_encoder_disable
,
220 .mode_set
= zx_tvenc_encoder_mode_set
,
223 static const struct drm_encoder_funcs zx_tvenc_encoder_funcs
= {
224 .destroy
= drm_encoder_cleanup
,
227 static int zx_tvenc_connector_get_modes(struct drm_connector
*connector
)
229 struct zx_tvenc
*tvenc
= to_zx_tvenc(connector
);
230 struct device
*dev
= tvenc
->dev
;
233 for (i
= 0; i
< ARRAY_SIZE(tvenc_modes
); i
++) {
234 const struct zx_tvenc_mode
*zmode
= tvenc_modes
[i
];
235 struct drm_display_mode
*mode
;
237 mode
= drm_mode_duplicate(connector
->dev
, &zmode
->mode
);
239 DRM_DEV_ERROR(dev
, "failed to duplicate drm mode\n");
243 drm_mode_set_name(mode
);
244 drm_mode_probed_add(connector
, mode
);
250 static enum drm_mode_status
251 zx_tvenc_connector_mode_valid(struct drm_connector
*connector
,
252 struct drm_display_mode
*mode
)
254 struct zx_tvenc
*tvenc
= to_zx_tvenc(connector
);
255 const struct zx_tvenc_mode
*zmode
;
257 zmode
= zx_tvenc_find_zmode(mode
);
259 DRM_DEV_ERROR(tvenc
->dev
, "unsupported mode: %s\n", mode
->name
);
266 static struct drm_connector_helper_funcs zx_tvenc_connector_helper_funcs
= {
267 .get_modes
= zx_tvenc_connector_get_modes
,
268 .mode_valid
= zx_tvenc_connector_mode_valid
,
271 static const struct drm_connector_funcs zx_tvenc_connector_funcs
= {
272 .fill_modes
= drm_helper_probe_single_connector_modes
,
273 .destroy
= drm_connector_cleanup
,
274 .reset
= drm_atomic_helper_connector_reset
,
275 .atomic_duplicate_state
= drm_atomic_helper_connector_duplicate_state
,
276 .atomic_destroy_state
= drm_atomic_helper_connector_destroy_state
,
279 static int zx_tvenc_register(struct drm_device
*drm
, struct zx_tvenc
*tvenc
)
281 struct drm_encoder
*encoder
= &tvenc
->encoder
;
282 struct drm_connector
*connector
= &tvenc
->connector
;
285 * The tvenc is designed to use aux channel, as there is a deflicker
286 * block for the channel.
288 encoder
->possible_crtcs
= BIT(1);
290 drm_encoder_init(drm
, encoder
, &zx_tvenc_encoder_funcs
,
291 DRM_MODE_ENCODER_TVDAC
, NULL
);
292 drm_encoder_helper_add(encoder
, &zx_tvenc_encoder_helper_funcs
);
294 connector
->interlace_allowed
= true;
296 drm_connector_init(drm
, connector
, &zx_tvenc_connector_funcs
,
297 DRM_MODE_CONNECTOR_Composite
);
298 drm_connector_helper_add(connector
, &zx_tvenc_connector_helper_funcs
);
300 drm_connector_attach_encoder(connector
, encoder
);
305 static int zx_tvenc_pwrctrl_init(struct zx_tvenc
*tvenc
)
307 struct zx_tvenc_pwrctrl
*pwrctrl
= &tvenc
->pwrctrl
;
308 struct device
*dev
= tvenc
->dev
;
309 struct of_phandle_args out_args
;
310 struct regmap
*regmap
;
313 ret
= of_parse_phandle_with_fixed_args(dev
->of_node
,
314 "zte,tvenc-power-control", 2, 0, &out_args
);
318 regmap
= syscon_node_to_regmap(out_args
.np
);
319 if (IS_ERR(regmap
)) {
320 ret
= PTR_ERR(regmap
);
324 pwrctrl
->regmap
= regmap
;
325 pwrctrl
->reg
= out_args
.args
[0];
326 pwrctrl
->mask
= out_args
.args
[1];
329 of_node_put(out_args
.np
);
333 static int zx_tvenc_bind(struct device
*dev
, struct device
*master
, void *data
)
335 struct platform_device
*pdev
= to_platform_device(dev
);
336 struct drm_device
*drm
= data
;
337 struct resource
*res
;
338 struct zx_tvenc
*tvenc
;
341 tvenc
= devm_kzalloc(dev
, sizeof(*tvenc
), GFP_KERNEL
);
346 dev_set_drvdata(dev
, tvenc
);
348 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
349 tvenc
->mmio
= devm_ioremap_resource(dev
, res
);
350 if (IS_ERR(tvenc
->mmio
)) {
351 ret
= PTR_ERR(tvenc
->mmio
);
352 DRM_DEV_ERROR(dev
, "failed to remap tvenc region: %d\n", ret
);
356 ret
= zx_tvenc_pwrctrl_init(tvenc
);
358 DRM_DEV_ERROR(dev
, "failed to init power control: %d\n", ret
);
362 ret
= zx_tvenc_register(drm
, tvenc
);
364 DRM_DEV_ERROR(dev
, "failed to register tvenc: %d\n", ret
);
371 static void zx_tvenc_unbind(struct device
*dev
, struct device
*master
,
377 static const struct component_ops zx_tvenc_component_ops
= {
378 .bind
= zx_tvenc_bind
,
379 .unbind
= zx_tvenc_unbind
,
382 static int zx_tvenc_probe(struct platform_device
*pdev
)
384 return component_add(&pdev
->dev
, &zx_tvenc_component_ops
);
387 static int zx_tvenc_remove(struct platform_device
*pdev
)
389 component_del(&pdev
->dev
, &zx_tvenc_component_ops
);
393 static const struct of_device_id zx_tvenc_of_match
[] = {
394 { .compatible
= "zte,zx296718-tvenc", },
397 MODULE_DEVICE_TABLE(of
, zx_tvenc_of_match
);
399 struct platform_driver zx_tvenc_driver
= {
400 .probe
= zx_tvenc_probe
,
401 .remove
= zx_tvenc_remove
,
404 .of_match_table
= zx_tvenc_of_match
,