923 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2009 Nokia Corporation4 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>5 *6 * VENC settings from TI's DSS driver7 */8 9#define DSS_SUBSYS_NAME "VENC"10 11#include <linux/kernel.h>12#include <linux/module.h>13#include <linux/clk.h>14#include <linux/err.h>15#include <linux/io.h>16#include <linux/completion.h>17#include <linux/delay.h>18#include <linux/string.h>19#include <linux/seq_file.h>20#include <linux/platform_device.h>21#include <linux/regulator/consumer.h>22#include <linux/pm_runtime.h>23#include <linux/of.h>24#include <linux/of_graph.h>25#include <linux/component.h>26#include <linux/sys_soc.h>27 28#include <drm/drm_bridge.h>29 30#include "omapdss.h"31#include "dss.h"32 33/* Venc registers */34#define VENC_REV_ID 0x0035#define VENC_STATUS 0x0436#define VENC_F_CONTROL 0x0837#define VENC_VIDOUT_CTRL 0x1038#define VENC_SYNC_CTRL 0x1439#define VENC_LLEN 0x1C40#define VENC_FLENS 0x2041#define VENC_HFLTR_CTRL 0x2442#define VENC_CC_CARR_WSS_CARR 0x2843#define VENC_C_PHASE 0x2C44#define VENC_GAIN_U 0x3045#define VENC_GAIN_V 0x3446#define VENC_GAIN_Y 0x3847#define VENC_BLACK_LEVEL 0x3C48#define VENC_BLANK_LEVEL 0x4049#define VENC_X_COLOR 0x4450#define VENC_M_CONTROL 0x4851#define VENC_BSTAMP_WSS_DATA 0x4C52#define VENC_S_CARR 0x5053#define VENC_LINE21 0x5454#define VENC_LN_SEL 0x5855#define VENC_L21__WC_CTL 0x5C56#define VENC_HTRIGGER_VTRIGGER 0x6057#define VENC_SAVID__EAVID 0x6458#define VENC_FLEN__FAL 0x6859#define VENC_LAL__PHASE_RESET 0x6C60#define VENC_HS_INT_START_STOP_X 0x7061#define VENC_HS_EXT_START_STOP_X 0x7462#define VENC_VS_INT_START_X 0x7863#define VENC_VS_INT_STOP_X__VS_INT_START_Y 0x7C64#define VENC_VS_INT_STOP_Y__VS_EXT_START_X 0x8065#define VENC_VS_EXT_STOP_X__VS_EXT_START_Y 0x8466#define VENC_VS_EXT_STOP_Y 0x8867#define VENC_AVID_START_STOP_X 0x9068#define VENC_AVID_START_STOP_Y 0x9469#define VENC_FID_INT_START_X__FID_INT_START_Y 0xA070#define VENC_FID_INT_OFFSET_Y__FID_EXT_START_X 0xA471#define VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y 0xA872#define VENC_TVDETGP_INT_START_STOP_X 0xB073#define VENC_TVDETGP_INT_START_STOP_Y 0xB474#define VENC_GEN_CTRL 0xB875#define VENC_OUTPUT_CONTROL 0xC476#define VENC_OUTPUT_TEST 0xC877#define VENC_DAC_B__DAC_C 0xC878 79struct venc_config {80 u32 f_control;81 u32 vidout_ctrl;82 u32 sync_ctrl;83 u32 llen;84 u32 flens;85 u32 hfltr_ctrl;86 u32 cc_carr_wss_carr;87 u32 c_phase;88 u32 gain_u;89 u32 gain_v;90 u32 gain_y;91 u32 black_level;92 u32 blank_level;93 u32 x_color;94 u32 m_control;95 u32 bstamp_wss_data;96 u32 s_carr;97 u32 line21;98 u32 ln_sel;99 u32 l21__wc_ctl;100 u32 htrigger_vtrigger;101 u32 savid__eavid;102 u32 flen__fal;103 u32 lal__phase_reset;104 u32 hs_int_start_stop_x;105 u32 hs_ext_start_stop_x;106 u32 vs_int_start_x;107 u32 vs_int_stop_x__vs_int_start_y;108 u32 vs_int_stop_y__vs_ext_start_x;109 u32 vs_ext_stop_x__vs_ext_start_y;110 u32 vs_ext_stop_y;111 u32 avid_start_stop_x;112 u32 avid_start_stop_y;113 u32 fid_int_start_x__fid_int_start_y;114 u32 fid_int_offset_y__fid_ext_start_x;115 u32 fid_ext_start_y__fid_ext_offset_y;116 u32 tvdetgp_int_start_stop_x;117 u32 tvdetgp_int_start_stop_y;118 u32 gen_ctrl;119};120 121/* from TRM */122static const struct venc_config venc_config_pal_trm = {123 .f_control = 0,124 .vidout_ctrl = 1,125 .sync_ctrl = 0x40,126 .llen = 0x35F, /* 863 */127 .flens = 0x270, /* 624 */128 .hfltr_ctrl = 0,129 .cc_carr_wss_carr = 0x2F7225ED,130 .c_phase = 0,131 .gain_u = 0x111,132 .gain_v = 0x181,133 .gain_y = 0x140,134 .black_level = 0x3B,135 .blank_level = 0x3B,136 .x_color = 0x7,137 .m_control = 0x2,138 .bstamp_wss_data = 0x3F,139 .s_carr = 0x2A098ACB,140 .line21 = 0,141 .ln_sel = 0x01290015,142 .l21__wc_ctl = 0x0000F603,143 .htrigger_vtrigger = 0,144 145 .savid__eavid = 0x06A70108,146 .flen__fal = 0x00180270,147 .lal__phase_reset = 0x00040135,148 .hs_int_start_stop_x = 0x00880358,149 .hs_ext_start_stop_x = 0x000F035F,150 .vs_int_start_x = 0x01A70000,151 .vs_int_stop_x__vs_int_start_y = 0x000001A7,152 .vs_int_stop_y__vs_ext_start_x = 0x01AF0000,153 .vs_ext_stop_x__vs_ext_start_y = 0x000101AF,154 .vs_ext_stop_y = 0x00000025,155 .avid_start_stop_x = 0x03530083,156 .avid_start_stop_y = 0x026C002E,157 .fid_int_start_x__fid_int_start_y = 0x0001008A,158 .fid_int_offset_y__fid_ext_start_x = 0x002E0138,159 .fid_ext_start_y__fid_ext_offset_y = 0x01380001,160 161 .tvdetgp_int_start_stop_x = 0x00140001,162 .tvdetgp_int_start_stop_y = 0x00010001,163 .gen_ctrl = 0x00FF0000,164};165 166/* from TRM */167static const struct venc_config venc_config_ntsc_trm = {168 .f_control = 0,169 .vidout_ctrl = 1,170 .sync_ctrl = 0x8040,171 .llen = 0x359,172 .flens = 0x20C,173 .hfltr_ctrl = 0,174 .cc_carr_wss_carr = 0x043F2631,175 .c_phase = 0,176 .gain_u = 0x102,177 .gain_v = 0x16C,178 .gain_y = 0x12F,179 .black_level = 0x43,180 .blank_level = 0x38,181 .x_color = 0x7,182 .m_control = 0x1,183 .bstamp_wss_data = 0x38,184 .s_carr = 0x21F07C1F,185 .line21 = 0,186 .ln_sel = 0x01310011,187 .l21__wc_ctl = 0x0000F003,188 .htrigger_vtrigger = 0,189 190 .savid__eavid = 0x069300F4,191 .flen__fal = 0x0016020C,192 .lal__phase_reset = 0x00060107,193 .hs_int_start_stop_x = 0x008E0350,194 .hs_ext_start_stop_x = 0x000F0359,195 .vs_int_start_x = 0x01A00000,196 .vs_int_stop_x__vs_int_start_y = 0x020701A0,197 .vs_int_stop_y__vs_ext_start_x = 0x01AC0024,198 .vs_ext_stop_x__vs_ext_start_y = 0x020D01AC,199 .vs_ext_stop_y = 0x00000006,200 .avid_start_stop_x = 0x03480078,201 .avid_start_stop_y = 0x02060024,202 .fid_int_start_x__fid_int_start_y = 0x0001008A,203 .fid_int_offset_y__fid_ext_start_x = 0x01AC0106,204 .fid_ext_start_y__fid_ext_offset_y = 0x01060006,205 206 .tvdetgp_int_start_stop_x = 0x00140001,207 .tvdetgp_int_start_stop_y = 0x00010001,208 .gen_ctrl = 0x00F90000,209};210 211enum venc_videomode {212 VENC_MODE_UNKNOWN,213 VENC_MODE_PAL,214 VENC_MODE_NTSC,215};216 217static const struct drm_display_mode omap_dss_pal_mode = {218 .hdisplay = 720,219 .hsync_start = 732,220 .hsync_end = 796,221 .htotal = 864,222 .vdisplay = 574,223 .vsync_start = 579,224 .vsync_end = 584,225 .vtotal = 625,226 .clock = 13500,227 228 .flags = DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_NHSYNC |229 DRM_MODE_FLAG_NVSYNC,230};231 232static const struct drm_display_mode omap_dss_ntsc_mode = {233 .hdisplay = 720,234 .hsync_start = 736,235 .hsync_end = 800,236 .htotal = 858,237 .vdisplay = 482,238 .vsync_start = 488,239 .vsync_end = 494,240 .vtotal = 525,241 .clock = 13500,242 243 .flags = DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_NHSYNC |244 DRM_MODE_FLAG_NVSYNC,245};246 247struct venc_device {248 struct platform_device *pdev;249 void __iomem *base;250 struct regulator *vdda_dac_reg;251 struct dss_device *dss;252 253 struct dss_debugfs_entry *debugfs;254 255 struct clk *tv_dac_clk;256 257 const struct venc_config *config;258 enum omap_dss_venc_type type;259 bool invert_polarity;260 bool requires_tv_dac_clk;261 262 struct omap_dss_device output;263 struct drm_bridge bridge;264};265 266#define drm_bridge_to_venc(b) container_of(b, struct venc_device, bridge)267 268static inline void venc_write_reg(struct venc_device *venc, int idx, u32 val)269{270 __raw_writel(val, venc->base + idx);271}272 273static inline u32 venc_read_reg(struct venc_device *venc, int idx)274{275 u32 l = __raw_readl(venc->base + idx);276 return l;277}278 279static void venc_write_config(struct venc_device *venc,280 const struct venc_config *config)281{282 DSSDBG("write venc conf\n");283 284 venc_write_reg(venc, VENC_LLEN, config->llen);285 venc_write_reg(venc, VENC_FLENS, config->flens);286 venc_write_reg(venc, VENC_CC_CARR_WSS_CARR, config->cc_carr_wss_carr);287 venc_write_reg(venc, VENC_C_PHASE, config->c_phase);288 venc_write_reg(venc, VENC_GAIN_U, config->gain_u);289 venc_write_reg(venc, VENC_GAIN_V, config->gain_v);290 venc_write_reg(venc, VENC_GAIN_Y, config->gain_y);291 venc_write_reg(venc, VENC_BLACK_LEVEL, config->black_level);292 venc_write_reg(venc, VENC_BLANK_LEVEL, config->blank_level);293 venc_write_reg(venc, VENC_M_CONTROL, config->m_control);294 venc_write_reg(venc, VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data);295 venc_write_reg(venc, VENC_S_CARR, config->s_carr);296 venc_write_reg(venc, VENC_L21__WC_CTL, config->l21__wc_ctl);297 venc_write_reg(venc, VENC_SAVID__EAVID, config->savid__eavid);298 venc_write_reg(venc, VENC_FLEN__FAL, config->flen__fal);299 venc_write_reg(venc, VENC_LAL__PHASE_RESET, config->lal__phase_reset);300 venc_write_reg(venc, VENC_HS_INT_START_STOP_X,301 config->hs_int_start_stop_x);302 venc_write_reg(venc, VENC_HS_EXT_START_STOP_X,303 config->hs_ext_start_stop_x);304 venc_write_reg(venc, VENC_VS_INT_START_X, config->vs_int_start_x);305 venc_write_reg(venc, VENC_VS_INT_STOP_X__VS_INT_START_Y,306 config->vs_int_stop_x__vs_int_start_y);307 venc_write_reg(venc, VENC_VS_INT_STOP_Y__VS_EXT_START_X,308 config->vs_int_stop_y__vs_ext_start_x);309 venc_write_reg(venc, VENC_VS_EXT_STOP_X__VS_EXT_START_Y,310 config->vs_ext_stop_x__vs_ext_start_y);311 venc_write_reg(venc, VENC_VS_EXT_STOP_Y, config->vs_ext_stop_y);312 venc_write_reg(venc, VENC_AVID_START_STOP_X, config->avid_start_stop_x);313 venc_write_reg(venc, VENC_AVID_START_STOP_Y, config->avid_start_stop_y);314 venc_write_reg(venc, VENC_FID_INT_START_X__FID_INT_START_Y,315 config->fid_int_start_x__fid_int_start_y);316 venc_write_reg(venc, VENC_FID_INT_OFFSET_Y__FID_EXT_START_X,317 config->fid_int_offset_y__fid_ext_start_x);318 venc_write_reg(venc, VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y,319 config->fid_ext_start_y__fid_ext_offset_y);320 321 venc_write_reg(venc, VENC_DAC_B__DAC_C,322 venc_read_reg(venc, VENC_DAC_B__DAC_C));323 venc_write_reg(venc, VENC_VIDOUT_CTRL, config->vidout_ctrl);324 venc_write_reg(venc, VENC_HFLTR_CTRL, config->hfltr_ctrl);325 venc_write_reg(venc, VENC_X_COLOR, config->x_color);326 venc_write_reg(venc, VENC_LINE21, config->line21);327 venc_write_reg(venc, VENC_LN_SEL, config->ln_sel);328 venc_write_reg(venc, VENC_HTRIGGER_VTRIGGER, config->htrigger_vtrigger);329 venc_write_reg(venc, VENC_TVDETGP_INT_START_STOP_X,330 config->tvdetgp_int_start_stop_x);331 venc_write_reg(venc, VENC_TVDETGP_INT_START_STOP_Y,332 config->tvdetgp_int_start_stop_y);333 venc_write_reg(venc, VENC_GEN_CTRL, config->gen_ctrl);334 venc_write_reg(venc, VENC_F_CONTROL, config->f_control);335 venc_write_reg(venc, VENC_SYNC_CTRL, config->sync_ctrl);336}337 338static void venc_reset(struct venc_device *venc)339{340 int t = 1000;341 342 venc_write_reg(venc, VENC_F_CONTROL, 1<<8);343 while (venc_read_reg(venc, VENC_F_CONTROL) & (1<<8)) {344 if (--t == 0) {345 DSSERR("Failed to reset venc\n");346 return;347 }348 }349 350#ifdef CONFIG_OMAP2_DSS_SLEEP_AFTER_VENC_RESET351 /* the magical sleep that makes things work */352 /* XXX more info? What bug this circumvents? */353 msleep(20);354#endif355}356 357static int venc_runtime_get(struct venc_device *venc)358{359 int r;360 361 DSSDBG("venc_runtime_get\n");362 363 r = pm_runtime_get_sync(&venc->pdev->dev);364 if (WARN_ON(r < 0)) {365 pm_runtime_put_noidle(&venc->pdev->dev);366 return r;367 }368 return 0;369}370 371static void venc_runtime_put(struct venc_device *venc)372{373 int r;374 375 DSSDBG("venc_runtime_put\n");376 377 r = pm_runtime_put_sync(&venc->pdev->dev);378 WARN_ON(r < 0 && r != -ENOSYS);379}380 381static int venc_power_on(struct venc_device *venc)382{383 u32 l;384 int r;385 386 r = venc_runtime_get(venc);387 if (r)388 goto err0;389 390 venc_reset(venc);391 venc_write_config(venc, venc->config);392 393 dss_set_venc_output(venc->dss, venc->type);394 dss_set_dac_pwrdn_bgz(venc->dss, 1);395 396 l = 0;397 398 if (venc->type == OMAP_DSS_VENC_TYPE_COMPOSITE)399 l |= 1 << 1;400 else /* S-Video */401 l |= (1 << 0) | (1 << 2);402 403 if (venc->invert_polarity == false)404 l |= 1 << 3;405 406 venc_write_reg(venc, VENC_OUTPUT_CONTROL, l);407 408 r = regulator_enable(venc->vdda_dac_reg);409 if (r)410 goto err1;411 412 r = dss_mgr_enable(&venc->output);413 if (r)414 goto err2;415 416 return 0;417 418err2:419 regulator_disable(venc->vdda_dac_reg);420err1:421 venc_write_reg(venc, VENC_OUTPUT_CONTROL, 0);422 dss_set_dac_pwrdn_bgz(venc->dss, 0);423 424 venc_runtime_put(venc);425err0:426 return r;427}428 429static void venc_power_off(struct venc_device *venc)430{431 venc_write_reg(venc, VENC_OUTPUT_CONTROL, 0);432 dss_set_dac_pwrdn_bgz(venc->dss, 0);433 434 dss_mgr_disable(&venc->output);435 436 regulator_disable(venc->vdda_dac_reg);437 438 venc_runtime_put(venc);439}440 441static enum venc_videomode venc_get_videomode(const struct drm_display_mode *mode)442{443 if (!(mode->flags & DRM_MODE_FLAG_INTERLACE))444 return VENC_MODE_UNKNOWN;445 446 if (mode->clock == omap_dss_pal_mode.clock &&447 mode->hdisplay == omap_dss_pal_mode.hdisplay &&448 mode->vdisplay == omap_dss_pal_mode.vdisplay)449 return VENC_MODE_PAL;450 451 if (mode->clock == omap_dss_ntsc_mode.clock &&452 mode->hdisplay == omap_dss_ntsc_mode.hdisplay &&453 mode->vdisplay == omap_dss_ntsc_mode.vdisplay)454 return VENC_MODE_NTSC;455 456 return VENC_MODE_UNKNOWN;457}458 459static int venc_dump_regs(struct seq_file *s, void *p)460{461 struct venc_device *venc = s->private;462 463#define DUMPREG(venc, r) \464 seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(venc, r))465 466 if (venc_runtime_get(venc))467 return 0;468 469 DUMPREG(venc, VENC_F_CONTROL);470 DUMPREG(venc, VENC_VIDOUT_CTRL);471 DUMPREG(venc, VENC_SYNC_CTRL);472 DUMPREG(venc, VENC_LLEN);473 DUMPREG(venc, VENC_FLENS);474 DUMPREG(venc, VENC_HFLTR_CTRL);475 DUMPREG(venc, VENC_CC_CARR_WSS_CARR);476 DUMPREG(venc, VENC_C_PHASE);477 DUMPREG(venc, VENC_GAIN_U);478 DUMPREG(venc, VENC_GAIN_V);479 DUMPREG(venc, VENC_GAIN_Y);480 DUMPREG(venc, VENC_BLACK_LEVEL);481 DUMPREG(venc, VENC_BLANK_LEVEL);482 DUMPREG(venc, VENC_X_COLOR);483 DUMPREG(venc, VENC_M_CONTROL);484 DUMPREG(venc, VENC_BSTAMP_WSS_DATA);485 DUMPREG(venc, VENC_S_CARR);486 DUMPREG(venc, VENC_LINE21);487 DUMPREG(venc, VENC_LN_SEL);488 DUMPREG(venc, VENC_L21__WC_CTL);489 DUMPREG(venc, VENC_HTRIGGER_VTRIGGER);490 DUMPREG(venc, VENC_SAVID__EAVID);491 DUMPREG(venc, VENC_FLEN__FAL);492 DUMPREG(venc, VENC_LAL__PHASE_RESET);493 DUMPREG(venc, VENC_HS_INT_START_STOP_X);494 DUMPREG(venc, VENC_HS_EXT_START_STOP_X);495 DUMPREG(venc, VENC_VS_INT_START_X);496 DUMPREG(venc, VENC_VS_INT_STOP_X__VS_INT_START_Y);497 DUMPREG(venc, VENC_VS_INT_STOP_Y__VS_EXT_START_X);498 DUMPREG(venc, VENC_VS_EXT_STOP_X__VS_EXT_START_Y);499 DUMPREG(venc, VENC_VS_EXT_STOP_Y);500 DUMPREG(venc, VENC_AVID_START_STOP_X);501 DUMPREG(venc, VENC_AVID_START_STOP_Y);502 DUMPREG(venc, VENC_FID_INT_START_X__FID_INT_START_Y);503 DUMPREG(venc, VENC_FID_INT_OFFSET_Y__FID_EXT_START_X);504 DUMPREG(venc, VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y);505 DUMPREG(venc, VENC_TVDETGP_INT_START_STOP_X);506 DUMPREG(venc, VENC_TVDETGP_INT_START_STOP_Y);507 DUMPREG(venc, VENC_GEN_CTRL);508 DUMPREG(venc, VENC_OUTPUT_CONTROL);509 DUMPREG(venc, VENC_OUTPUT_TEST);510 511 venc_runtime_put(venc);512 513#undef DUMPREG514 return 0;515}516 517static int venc_get_clocks(struct venc_device *venc)518{519 struct clk *clk;520 521 if (venc->requires_tv_dac_clk) {522 clk = devm_clk_get(&venc->pdev->dev, "tv_dac_clk");523 if (IS_ERR(clk)) {524 DSSERR("can't get tv_dac_clk\n");525 return PTR_ERR(clk);526 }527 } else {528 clk = NULL;529 }530 531 venc->tv_dac_clk = clk;532 533 return 0;534}535 536/* -----------------------------------------------------------------------------537 * DRM Bridge Operations538 */539 540static int venc_bridge_attach(struct drm_bridge *bridge,541 enum drm_bridge_attach_flags flags)542{543 struct venc_device *venc = drm_bridge_to_venc(bridge);544 545 if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))546 return -EINVAL;547 548 return drm_bridge_attach(bridge->encoder, venc->output.next_bridge,549 bridge, flags);550}551 552static enum drm_mode_status553venc_bridge_mode_valid(struct drm_bridge *bridge,554 const struct drm_display_info *info,555 const struct drm_display_mode *mode)556{557 switch (venc_get_videomode(mode)) {558 case VENC_MODE_PAL:559 case VENC_MODE_NTSC:560 return MODE_OK;561 562 default:563 return MODE_BAD;564 }565}566 567static bool venc_bridge_mode_fixup(struct drm_bridge *bridge,568 const struct drm_display_mode *mode,569 struct drm_display_mode *adjusted_mode)570{571 const struct drm_display_mode *venc_mode;572 573 switch (venc_get_videomode(adjusted_mode)) {574 case VENC_MODE_PAL:575 venc_mode = &omap_dss_pal_mode;576 break;577 578 case VENC_MODE_NTSC:579 venc_mode = &omap_dss_ntsc_mode;580 break;581 582 default:583 return false;584 }585 586 drm_mode_copy(adjusted_mode, venc_mode);587 drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);588 drm_mode_set_name(adjusted_mode);589 590 return true;591}592 593static void venc_bridge_mode_set(struct drm_bridge *bridge,594 const struct drm_display_mode *mode,595 const struct drm_display_mode *adjusted_mode)596{597 struct venc_device *venc = drm_bridge_to_venc(bridge);598 enum venc_videomode venc_mode = venc_get_videomode(adjusted_mode);599 600 switch (venc_mode) {601 default:602 WARN_ON_ONCE(1);603 fallthrough;604 case VENC_MODE_PAL:605 venc->config = &venc_config_pal_trm;606 break;607 608 case VENC_MODE_NTSC:609 venc->config = &venc_config_ntsc_trm;610 break;611 }612 613 dispc_set_tv_pclk(venc->dss->dispc, 13500000);614}615 616static void venc_bridge_enable(struct drm_bridge *bridge)617{618 struct venc_device *venc = drm_bridge_to_venc(bridge);619 620 venc_power_on(venc);621}622 623static void venc_bridge_disable(struct drm_bridge *bridge)624{625 struct venc_device *venc = drm_bridge_to_venc(bridge);626 627 venc_power_off(venc);628}629 630static int venc_bridge_get_modes(struct drm_bridge *bridge,631 struct drm_connector *connector)632{633 static const struct drm_display_mode *modes[] = {634 &omap_dss_pal_mode,635 &omap_dss_ntsc_mode,636 };637 unsigned int i;638 639 for (i = 0; i < ARRAY_SIZE(modes); ++i) {640 struct drm_display_mode *mode;641 642 mode = drm_mode_duplicate(connector->dev, modes[i]);643 if (!mode)644 return i;645 646 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;647 drm_mode_set_name(mode);648 drm_mode_probed_add(connector, mode);649 }650 651 return ARRAY_SIZE(modes);652}653 654static const struct drm_bridge_funcs venc_bridge_funcs = {655 .attach = venc_bridge_attach,656 .mode_valid = venc_bridge_mode_valid,657 .mode_fixup = venc_bridge_mode_fixup,658 .mode_set = venc_bridge_mode_set,659 .enable = venc_bridge_enable,660 .disable = venc_bridge_disable,661 .get_modes = venc_bridge_get_modes,662};663 664static void venc_bridge_init(struct venc_device *venc)665{666 venc->bridge.funcs = &venc_bridge_funcs;667 venc->bridge.of_node = venc->pdev->dev.of_node;668 venc->bridge.ops = DRM_BRIDGE_OP_MODES;669 venc->bridge.type = DRM_MODE_CONNECTOR_SVIDEO;670 venc->bridge.interlace_allowed = true;671 672 drm_bridge_add(&venc->bridge);673}674 675static void venc_bridge_cleanup(struct venc_device *venc)676{677 drm_bridge_remove(&venc->bridge);678}679 680/* -----------------------------------------------------------------------------681 * Component Bind & Unbind682 */683 684static int venc_bind(struct device *dev, struct device *master, void *data)685{686 struct dss_device *dss = dss_get_device(master);687 struct venc_device *venc = dev_get_drvdata(dev);688 u8 rev_id;689 int r;690 691 venc->dss = dss;692 693 r = venc_runtime_get(venc);694 if (r)695 return r;696 697 rev_id = (u8)(venc_read_reg(venc, VENC_REV_ID) & 0xff);698 dev_dbg(dev, "OMAP VENC rev %d\n", rev_id);699 700 venc_runtime_put(venc);701 702 venc->debugfs = dss_debugfs_create_file(dss, "venc", venc_dump_regs,703 venc);704 705 return 0;706}707 708static void venc_unbind(struct device *dev, struct device *master, void *data)709{710 struct venc_device *venc = dev_get_drvdata(dev);711 712 dss_debugfs_remove_file(venc->debugfs);713}714 715static const struct component_ops venc_component_ops = {716 .bind = venc_bind,717 .unbind = venc_unbind,718};719 720/* -----------------------------------------------------------------------------721 * Probe & Remove, Suspend & Resume722 */723 724static int venc_init_output(struct venc_device *venc)725{726 struct omap_dss_device *out = &venc->output;727 int r;728 729 venc_bridge_init(venc);730 731 out->dev = &venc->pdev->dev;732 out->id = OMAP_DSS_OUTPUT_VENC;733 out->type = OMAP_DISPLAY_TYPE_VENC;734 out->name = "venc.0";735 out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;736 out->of_port = 0;737 738 r = omapdss_device_init_output(out, &venc->bridge);739 if (r < 0) {740 venc_bridge_cleanup(venc);741 return r;742 }743 744 omapdss_device_register(out);745 746 return 0;747}748 749static void venc_uninit_output(struct venc_device *venc)750{751 omapdss_device_unregister(&venc->output);752 omapdss_device_cleanup_output(&venc->output);753 754 venc_bridge_cleanup(venc);755}756 757static int venc_probe_of(struct venc_device *venc)758{759 struct device_node *node = venc->pdev->dev.of_node;760 struct device_node *ep;761 u32 channels;762 int r;763 764 ep = of_graph_get_endpoint_by_regs(node, 0, 0);765 if (!ep)766 return 0;767 768 venc->invert_polarity = of_property_read_bool(ep, "ti,invert-polarity");769 770 r = of_property_read_u32(ep, "ti,channels", &channels);771 if (r) {772 dev_err(&venc->pdev->dev,773 "failed to read property 'ti,channels': %d\n", r);774 goto err;775 }776 777 switch (channels) {778 case 1:779 venc->type = OMAP_DSS_VENC_TYPE_COMPOSITE;780 break;781 case 2:782 venc->type = OMAP_DSS_VENC_TYPE_SVIDEO;783 break;784 default:785 dev_err(&venc->pdev->dev, "bad channel property '%d'\n",786 channels);787 r = -EINVAL;788 goto err;789 }790 791 of_node_put(ep);792 793 return 0;794 795err:796 of_node_put(ep);797 return r;798}799 800static const struct soc_device_attribute venc_soc_devices[] = {801 { .machine = "OMAP3[45]*" },802 { .machine = "AM35*" },803 { /* sentinel */ }804};805 806static int venc_probe(struct platform_device *pdev)807{808 struct venc_device *venc;809 int r;810 811 venc = kzalloc(sizeof(*venc), GFP_KERNEL);812 if (!venc)813 return -ENOMEM;814 815 venc->pdev = pdev;816 817 platform_set_drvdata(pdev, venc);818 819 /* The OMAP34xx, OMAP35xx and AM35xx VENC require the TV DAC clock. */820 if (soc_device_match(venc_soc_devices))821 venc->requires_tv_dac_clk = true;822 823 venc->config = &venc_config_pal_trm;824 825 venc->base = devm_platform_ioremap_resource(pdev, 0);826 if (IS_ERR(venc->base)) {827 r = PTR_ERR(venc->base);828 goto err_free;829 }830 831 venc->vdda_dac_reg = devm_regulator_get(&pdev->dev, "vdda");832 if (IS_ERR(venc->vdda_dac_reg)) {833 r = PTR_ERR(venc->vdda_dac_reg);834 if (r != -EPROBE_DEFER)835 DSSERR("can't get VDDA_DAC regulator\n");836 goto err_free;837 }838 839 r = venc_get_clocks(venc);840 if (r)841 goto err_free;842 843 r = venc_probe_of(venc);844 if (r)845 goto err_free;846 847 pm_runtime_enable(&pdev->dev);848 849 r = venc_init_output(venc);850 if (r)851 goto err_pm_disable;852 853 r = component_add(&pdev->dev, &venc_component_ops);854 if (r)855 goto err_uninit_output;856 857 return 0;858 859err_uninit_output:860 venc_uninit_output(venc);861err_pm_disable:862 pm_runtime_disable(&pdev->dev);863err_free:864 kfree(venc);865 return r;866}867 868static void venc_remove(struct platform_device *pdev)869{870 struct venc_device *venc = platform_get_drvdata(pdev);871 872 component_del(&pdev->dev, &venc_component_ops);873 874 venc_uninit_output(venc);875 876 pm_runtime_disable(&pdev->dev);877 878 kfree(venc);879}880 881static __maybe_unused int venc_runtime_suspend(struct device *dev)882{883 struct venc_device *venc = dev_get_drvdata(dev);884 885 if (venc->tv_dac_clk)886 clk_disable_unprepare(venc->tv_dac_clk);887 888 return 0;889}890 891static __maybe_unused int venc_runtime_resume(struct device *dev)892{893 struct venc_device *venc = dev_get_drvdata(dev);894 895 if (venc->tv_dac_clk)896 clk_prepare_enable(venc->tv_dac_clk);897 898 return 0;899}900 901static const struct dev_pm_ops venc_pm_ops = {902 SET_RUNTIME_PM_OPS(venc_runtime_suspend, venc_runtime_resume, NULL)903 SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)904};905 906static const struct of_device_id venc_of_match[] = {907 { .compatible = "ti,omap2-venc", },908 { .compatible = "ti,omap3-venc", },909 { .compatible = "ti,omap4-venc", },910 {},911};912 913struct platform_driver omap_venchw_driver = {914 .probe = venc_probe,915 .remove_new = venc_remove,916 .driver = {917 .name = "omapdss_venc",918 .pm = &venc_pm_ops,919 .of_match_table = venc_of_match,920 .suppress_bind_attrs = true,921 },922};923