123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * Copyright (C) 2009 Nokia Corporation
- * Author: Tomi Valkeinen <[email protected]>
- *
- * VENC settings from TI's DSS driver
- */
- #define DSS_SUBSYS_NAME "VENC"
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/clk.h>
- #include <linux/err.h>
- #include <linux/io.h>
- #include <linux/completion.h>
- #include <linux/delay.h>
- #include <linux/string.h>
- #include <linux/seq_file.h>
- #include <linux/platform_device.h>
- #include <linux/regulator/consumer.h>
- #include <linux/pm_runtime.h>
- #include <linux/of.h>
- #include <linux/of_graph.h>
- #include <linux/component.h>
- #include <linux/sys_soc.h>
- #include <drm/drm_bridge.h>
- #include "omapdss.h"
- #include "dss.h"
- /* Venc registers */
- #define VENC_REV_ID 0x00
- #define VENC_STATUS 0x04
- #define VENC_F_CONTROL 0x08
- #define VENC_VIDOUT_CTRL 0x10
- #define VENC_SYNC_CTRL 0x14
- #define VENC_LLEN 0x1C
- #define VENC_FLENS 0x20
- #define VENC_HFLTR_CTRL 0x24
- #define VENC_CC_CARR_WSS_CARR 0x28
- #define VENC_C_PHASE 0x2C
- #define VENC_GAIN_U 0x30
- #define VENC_GAIN_V 0x34
- #define VENC_GAIN_Y 0x38
- #define VENC_BLACK_LEVEL 0x3C
- #define VENC_BLANK_LEVEL 0x40
- #define VENC_X_COLOR 0x44
- #define VENC_M_CONTROL 0x48
- #define VENC_BSTAMP_WSS_DATA 0x4C
- #define VENC_S_CARR 0x50
- #define VENC_LINE21 0x54
- #define VENC_LN_SEL 0x58
- #define VENC_L21__WC_CTL 0x5C
- #define VENC_HTRIGGER_VTRIGGER 0x60
- #define VENC_SAVID__EAVID 0x64
- #define VENC_FLEN__FAL 0x68
- #define VENC_LAL__PHASE_RESET 0x6C
- #define VENC_HS_INT_START_STOP_X 0x70
- #define VENC_HS_EXT_START_STOP_X 0x74
- #define VENC_VS_INT_START_X 0x78
- #define VENC_VS_INT_STOP_X__VS_INT_START_Y 0x7C
- #define VENC_VS_INT_STOP_Y__VS_EXT_START_X 0x80
- #define VENC_VS_EXT_STOP_X__VS_EXT_START_Y 0x84
- #define VENC_VS_EXT_STOP_Y 0x88
- #define VENC_AVID_START_STOP_X 0x90
- #define VENC_AVID_START_STOP_Y 0x94
- #define VENC_FID_INT_START_X__FID_INT_START_Y 0xA0
- #define VENC_FID_INT_OFFSET_Y__FID_EXT_START_X 0xA4
- #define VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y 0xA8
- #define VENC_TVDETGP_INT_START_STOP_X 0xB0
- #define VENC_TVDETGP_INT_START_STOP_Y 0xB4
- #define VENC_GEN_CTRL 0xB8
- #define VENC_OUTPUT_CONTROL 0xC4
- #define VENC_OUTPUT_TEST 0xC8
- #define VENC_DAC_B__DAC_C 0xC8
- struct venc_config {
- u32 f_control;
- u32 vidout_ctrl;
- u32 sync_ctrl;
- u32 llen;
- u32 flens;
- u32 hfltr_ctrl;
- u32 cc_carr_wss_carr;
- u32 c_phase;
- u32 gain_u;
- u32 gain_v;
- u32 gain_y;
- u32 black_level;
- u32 blank_level;
- u32 x_color;
- u32 m_control;
- u32 bstamp_wss_data;
- u32 s_carr;
- u32 line21;
- u32 ln_sel;
- u32 l21__wc_ctl;
- u32 htrigger_vtrigger;
- u32 savid__eavid;
- u32 flen__fal;
- u32 lal__phase_reset;
- u32 hs_int_start_stop_x;
- u32 hs_ext_start_stop_x;
- u32 vs_int_start_x;
- u32 vs_int_stop_x__vs_int_start_y;
- u32 vs_int_stop_y__vs_ext_start_x;
- u32 vs_ext_stop_x__vs_ext_start_y;
- u32 vs_ext_stop_y;
- u32 avid_start_stop_x;
- u32 avid_start_stop_y;
- u32 fid_int_start_x__fid_int_start_y;
- u32 fid_int_offset_y__fid_ext_start_x;
- u32 fid_ext_start_y__fid_ext_offset_y;
- u32 tvdetgp_int_start_stop_x;
- u32 tvdetgp_int_start_stop_y;
- u32 gen_ctrl;
- };
- /* from TRM */
- static const struct venc_config venc_config_pal_trm = {
- .f_control = 0,
- .vidout_ctrl = 1,
- .sync_ctrl = 0x40,
- .llen = 0x35F, /* 863 */
- .flens = 0x270, /* 624 */
- .hfltr_ctrl = 0,
- .cc_carr_wss_carr = 0x2F7225ED,
- .c_phase = 0,
- .gain_u = 0x111,
- .gain_v = 0x181,
- .gain_y = 0x140,
- .black_level = 0x3B,
- .blank_level = 0x3B,
- .x_color = 0x7,
- .m_control = 0x2,
- .bstamp_wss_data = 0x3F,
- .s_carr = 0x2A098ACB,
- .line21 = 0,
- .ln_sel = 0x01290015,
- .l21__wc_ctl = 0x0000F603,
- .htrigger_vtrigger = 0,
- .savid__eavid = 0x06A70108,
- .flen__fal = 0x00180270,
- .lal__phase_reset = 0x00040135,
- .hs_int_start_stop_x = 0x00880358,
- .hs_ext_start_stop_x = 0x000F035F,
- .vs_int_start_x = 0x01A70000,
- .vs_int_stop_x__vs_int_start_y = 0x000001A7,
- .vs_int_stop_y__vs_ext_start_x = 0x01AF0000,
- .vs_ext_stop_x__vs_ext_start_y = 0x000101AF,
- .vs_ext_stop_y = 0x00000025,
- .avid_start_stop_x = 0x03530083,
- .avid_start_stop_y = 0x026C002E,
- .fid_int_start_x__fid_int_start_y = 0x0001008A,
- .fid_int_offset_y__fid_ext_start_x = 0x002E0138,
- .fid_ext_start_y__fid_ext_offset_y = 0x01380001,
- .tvdetgp_int_start_stop_x = 0x00140001,
- .tvdetgp_int_start_stop_y = 0x00010001,
- .gen_ctrl = 0x00FF0000,
- };
- /* from TRM */
- static const struct venc_config venc_config_ntsc_trm = {
- .f_control = 0,
- .vidout_ctrl = 1,
- .sync_ctrl = 0x8040,
- .llen = 0x359,
- .flens = 0x20C,
- .hfltr_ctrl = 0,
- .cc_carr_wss_carr = 0x043F2631,
- .c_phase = 0,
- .gain_u = 0x102,
- .gain_v = 0x16C,
- .gain_y = 0x12F,
- .black_level = 0x43,
- .blank_level = 0x38,
- .x_color = 0x7,
- .m_control = 0x1,
- .bstamp_wss_data = 0x38,
- .s_carr = 0x21F07C1F,
- .line21 = 0,
- .ln_sel = 0x01310011,
- .l21__wc_ctl = 0x0000F003,
- .htrigger_vtrigger = 0,
- .savid__eavid = 0x069300F4,
- .flen__fal = 0x0016020C,
- .lal__phase_reset = 0x00060107,
- .hs_int_start_stop_x = 0x008E0350,
- .hs_ext_start_stop_x = 0x000F0359,
- .vs_int_start_x = 0x01A00000,
- .vs_int_stop_x__vs_int_start_y = 0x020701A0,
- .vs_int_stop_y__vs_ext_start_x = 0x01AC0024,
- .vs_ext_stop_x__vs_ext_start_y = 0x020D01AC,
- .vs_ext_stop_y = 0x00000006,
- .avid_start_stop_x = 0x03480078,
- .avid_start_stop_y = 0x02060024,
- .fid_int_start_x__fid_int_start_y = 0x0001008A,
- .fid_int_offset_y__fid_ext_start_x = 0x01AC0106,
- .fid_ext_start_y__fid_ext_offset_y = 0x01060006,
- .tvdetgp_int_start_stop_x = 0x00140001,
- .tvdetgp_int_start_stop_y = 0x00010001,
- .gen_ctrl = 0x00F90000,
- };
- enum venc_videomode {
- VENC_MODE_UNKNOWN,
- VENC_MODE_PAL,
- VENC_MODE_NTSC,
- };
- static const struct drm_display_mode omap_dss_pal_mode = {
- .hdisplay = 720,
- .hsync_start = 732,
- .hsync_end = 796,
- .htotal = 864,
- .vdisplay = 574,
- .vsync_start = 579,
- .vsync_end = 584,
- .vtotal = 625,
- .clock = 13500,
- .flags = DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_NHSYNC |
- DRM_MODE_FLAG_NVSYNC,
- };
- static const struct drm_display_mode omap_dss_ntsc_mode = {
- .hdisplay = 720,
- .hsync_start = 736,
- .hsync_end = 800,
- .htotal = 858,
- .vdisplay = 482,
- .vsync_start = 488,
- .vsync_end = 494,
- .vtotal = 525,
- .clock = 13500,
- .flags = DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_NHSYNC |
- DRM_MODE_FLAG_NVSYNC,
- };
- struct venc_device {
- struct platform_device *pdev;
- void __iomem *base;
- struct regulator *vdda_dac_reg;
- struct dss_device *dss;
- struct dss_debugfs_entry *debugfs;
- struct clk *tv_dac_clk;
- const struct venc_config *config;
- enum omap_dss_venc_type type;
- bool invert_polarity;
- bool requires_tv_dac_clk;
- struct omap_dss_device output;
- struct drm_bridge bridge;
- };
- #define drm_bridge_to_venc(b) container_of(b, struct venc_device, bridge)
- static inline void venc_write_reg(struct venc_device *venc, int idx, u32 val)
- {
- __raw_writel(val, venc->base + idx);
- }
- static inline u32 venc_read_reg(struct venc_device *venc, int idx)
- {
- u32 l = __raw_readl(venc->base + idx);
- return l;
- }
- static void venc_write_config(struct venc_device *venc,
- const struct venc_config *config)
- {
- DSSDBG("write venc conf\n");
- venc_write_reg(venc, VENC_LLEN, config->llen);
- venc_write_reg(venc, VENC_FLENS, config->flens);
- venc_write_reg(venc, VENC_CC_CARR_WSS_CARR, config->cc_carr_wss_carr);
- venc_write_reg(venc, VENC_C_PHASE, config->c_phase);
- venc_write_reg(venc, VENC_GAIN_U, config->gain_u);
- venc_write_reg(venc, VENC_GAIN_V, config->gain_v);
- venc_write_reg(venc, VENC_GAIN_Y, config->gain_y);
- venc_write_reg(venc, VENC_BLACK_LEVEL, config->black_level);
- venc_write_reg(venc, VENC_BLANK_LEVEL, config->blank_level);
- venc_write_reg(venc, VENC_M_CONTROL, config->m_control);
- venc_write_reg(venc, VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data);
- venc_write_reg(venc, VENC_S_CARR, config->s_carr);
- venc_write_reg(venc, VENC_L21__WC_CTL, config->l21__wc_ctl);
- venc_write_reg(venc, VENC_SAVID__EAVID, config->savid__eavid);
- venc_write_reg(venc, VENC_FLEN__FAL, config->flen__fal);
- venc_write_reg(venc, VENC_LAL__PHASE_RESET, config->lal__phase_reset);
- venc_write_reg(venc, VENC_HS_INT_START_STOP_X,
- config->hs_int_start_stop_x);
- venc_write_reg(venc, VENC_HS_EXT_START_STOP_X,
- config->hs_ext_start_stop_x);
- venc_write_reg(venc, VENC_VS_INT_START_X, config->vs_int_start_x);
- venc_write_reg(venc, VENC_VS_INT_STOP_X__VS_INT_START_Y,
- config->vs_int_stop_x__vs_int_start_y);
- venc_write_reg(venc, VENC_VS_INT_STOP_Y__VS_EXT_START_X,
- config->vs_int_stop_y__vs_ext_start_x);
- venc_write_reg(venc, VENC_VS_EXT_STOP_X__VS_EXT_START_Y,
- config->vs_ext_stop_x__vs_ext_start_y);
- venc_write_reg(venc, VENC_VS_EXT_STOP_Y, config->vs_ext_stop_y);
- venc_write_reg(venc, VENC_AVID_START_STOP_X, config->avid_start_stop_x);
- venc_write_reg(venc, VENC_AVID_START_STOP_Y, config->avid_start_stop_y);
- venc_write_reg(venc, VENC_FID_INT_START_X__FID_INT_START_Y,
- config->fid_int_start_x__fid_int_start_y);
- venc_write_reg(venc, VENC_FID_INT_OFFSET_Y__FID_EXT_START_X,
- config->fid_int_offset_y__fid_ext_start_x);
- venc_write_reg(venc, VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y,
- config->fid_ext_start_y__fid_ext_offset_y);
- venc_write_reg(venc, VENC_DAC_B__DAC_C,
- venc_read_reg(venc, VENC_DAC_B__DAC_C));
- venc_write_reg(venc, VENC_VIDOUT_CTRL, config->vidout_ctrl);
- venc_write_reg(venc, VENC_HFLTR_CTRL, config->hfltr_ctrl);
- venc_write_reg(venc, VENC_X_COLOR, config->x_color);
- venc_write_reg(venc, VENC_LINE21, config->line21);
- venc_write_reg(venc, VENC_LN_SEL, config->ln_sel);
- venc_write_reg(venc, VENC_HTRIGGER_VTRIGGER, config->htrigger_vtrigger);
- venc_write_reg(venc, VENC_TVDETGP_INT_START_STOP_X,
- config->tvdetgp_int_start_stop_x);
- venc_write_reg(venc, VENC_TVDETGP_INT_START_STOP_Y,
- config->tvdetgp_int_start_stop_y);
- venc_write_reg(venc, VENC_GEN_CTRL, config->gen_ctrl);
- venc_write_reg(venc, VENC_F_CONTROL, config->f_control);
- venc_write_reg(venc, VENC_SYNC_CTRL, config->sync_ctrl);
- }
- static void venc_reset(struct venc_device *venc)
- {
- int t = 1000;
- venc_write_reg(venc, VENC_F_CONTROL, 1<<8);
- while (venc_read_reg(venc, VENC_F_CONTROL) & (1<<8)) {
- if (--t == 0) {
- DSSERR("Failed to reset venc\n");
- return;
- }
- }
- #ifdef CONFIG_OMAP2_DSS_SLEEP_AFTER_VENC_RESET
- /* the magical sleep that makes things work */
- /* XXX more info? What bug this circumvents? */
- msleep(20);
- #endif
- }
- static int venc_runtime_get(struct venc_device *venc)
- {
- int r;
- DSSDBG("venc_runtime_get\n");
- r = pm_runtime_get_sync(&venc->pdev->dev);
- if (WARN_ON(r < 0)) {
- pm_runtime_put_noidle(&venc->pdev->dev);
- return r;
- }
- return 0;
- }
- static void venc_runtime_put(struct venc_device *venc)
- {
- int r;
- DSSDBG("venc_runtime_put\n");
- r = pm_runtime_put_sync(&venc->pdev->dev);
- WARN_ON(r < 0 && r != -ENOSYS);
- }
- static int venc_power_on(struct venc_device *venc)
- {
- u32 l;
- int r;
- r = venc_runtime_get(venc);
- if (r)
- goto err0;
- venc_reset(venc);
- venc_write_config(venc, venc->config);
- dss_set_venc_output(venc->dss, venc->type);
- dss_set_dac_pwrdn_bgz(venc->dss, 1);
- l = 0;
- if (venc->type == OMAP_DSS_VENC_TYPE_COMPOSITE)
- l |= 1 << 1;
- else /* S-Video */
- l |= (1 << 0) | (1 << 2);
- if (venc->invert_polarity == false)
- l |= 1 << 3;
- venc_write_reg(venc, VENC_OUTPUT_CONTROL, l);
- r = regulator_enable(venc->vdda_dac_reg);
- if (r)
- goto err1;
- r = dss_mgr_enable(&venc->output);
- if (r)
- goto err2;
- return 0;
- err2:
- regulator_disable(venc->vdda_dac_reg);
- err1:
- venc_write_reg(venc, VENC_OUTPUT_CONTROL, 0);
- dss_set_dac_pwrdn_bgz(venc->dss, 0);
- venc_runtime_put(venc);
- err0:
- return r;
- }
- static void venc_power_off(struct venc_device *venc)
- {
- venc_write_reg(venc, VENC_OUTPUT_CONTROL, 0);
- dss_set_dac_pwrdn_bgz(venc->dss, 0);
- dss_mgr_disable(&venc->output);
- regulator_disable(venc->vdda_dac_reg);
- venc_runtime_put(venc);
- }
- static enum venc_videomode venc_get_videomode(const struct drm_display_mode *mode)
- {
- if (!(mode->flags & DRM_MODE_FLAG_INTERLACE))
- return VENC_MODE_UNKNOWN;
- if (mode->clock == omap_dss_pal_mode.clock &&
- mode->hdisplay == omap_dss_pal_mode.hdisplay &&
- mode->vdisplay == omap_dss_pal_mode.vdisplay)
- return VENC_MODE_PAL;
- if (mode->clock == omap_dss_ntsc_mode.clock &&
- mode->hdisplay == omap_dss_ntsc_mode.hdisplay &&
- mode->vdisplay == omap_dss_ntsc_mode.vdisplay)
- return VENC_MODE_NTSC;
- return VENC_MODE_UNKNOWN;
- }
- static int venc_dump_regs(struct seq_file *s, void *p)
- {
- struct venc_device *venc = s->private;
- #define DUMPREG(venc, r) \
- seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(venc, r))
- if (venc_runtime_get(venc))
- return 0;
- DUMPREG(venc, VENC_F_CONTROL);
- DUMPREG(venc, VENC_VIDOUT_CTRL);
- DUMPREG(venc, VENC_SYNC_CTRL);
- DUMPREG(venc, VENC_LLEN);
- DUMPREG(venc, VENC_FLENS);
- DUMPREG(venc, VENC_HFLTR_CTRL);
- DUMPREG(venc, VENC_CC_CARR_WSS_CARR);
- DUMPREG(venc, VENC_C_PHASE);
- DUMPREG(venc, VENC_GAIN_U);
- DUMPREG(venc, VENC_GAIN_V);
- DUMPREG(venc, VENC_GAIN_Y);
- DUMPREG(venc, VENC_BLACK_LEVEL);
- DUMPREG(venc, VENC_BLANK_LEVEL);
- DUMPREG(venc, VENC_X_COLOR);
- DUMPREG(venc, VENC_M_CONTROL);
- DUMPREG(venc, VENC_BSTAMP_WSS_DATA);
- DUMPREG(venc, VENC_S_CARR);
- DUMPREG(venc, VENC_LINE21);
- DUMPREG(venc, VENC_LN_SEL);
- DUMPREG(venc, VENC_L21__WC_CTL);
- DUMPREG(venc, VENC_HTRIGGER_VTRIGGER);
- DUMPREG(venc, VENC_SAVID__EAVID);
- DUMPREG(venc, VENC_FLEN__FAL);
- DUMPREG(venc, VENC_LAL__PHASE_RESET);
- DUMPREG(venc, VENC_HS_INT_START_STOP_X);
- DUMPREG(venc, VENC_HS_EXT_START_STOP_X);
- DUMPREG(venc, VENC_VS_INT_START_X);
- DUMPREG(venc, VENC_VS_INT_STOP_X__VS_INT_START_Y);
- DUMPREG(venc, VENC_VS_INT_STOP_Y__VS_EXT_START_X);
- DUMPREG(venc, VENC_VS_EXT_STOP_X__VS_EXT_START_Y);
- DUMPREG(venc, VENC_VS_EXT_STOP_Y);
- DUMPREG(venc, VENC_AVID_START_STOP_X);
- DUMPREG(venc, VENC_AVID_START_STOP_Y);
- DUMPREG(venc, VENC_FID_INT_START_X__FID_INT_START_Y);
- DUMPREG(venc, VENC_FID_INT_OFFSET_Y__FID_EXT_START_X);
- DUMPREG(venc, VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y);
- DUMPREG(venc, VENC_TVDETGP_INT_START_STOP_X);
- DUMPREG(venc, VENC_TVDETGP_INT_START_STOP_Y);
- DUMPREG(venc, VENC_GEN_CTRL);
- DUMPREG(venc, VENC_OUTPUT_CONTROL);
- DUMPREG(venc, VENC_OUTPUT_TEST);
- venc_runtime_put(venc);
- #undef DUMPREG
- return 0;
- }
- static int venc_get_clocks(struct venc_device *venc)
- {
- struct clk *clk;
- if (venc->requires_tv_dac_clk) {
- clk = devm_clk_get(&venc->pdev->dev, "tv_dac_clk");
- if (IS_ERR(clk)) {
- DSSERR("can't get tv_dac_clk\n");
- return PTR_ERR(clk);
- }
- } else {
- clk = NULL;
- }
- venc->tv_dac_clk = clk;
- return 0;
- }
- /* -----------------------------------------------------------------------------
- * DRM Bridge Operations
- */
- static int venc_bridge_attach(struct drm_bridge *bridge,
- enum drm_bridge_attach_flags flags)
- {
- struct venc_device *venc = drm_bridge_to_venc(bridge);
- if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
- return -EINVAL;
- return drm_bridge_attach(bridge->encoder, venc->output.next_bridge,
- bridge, flags);
- }
- static enum drm_mode_status
- venc_bridge_mode_valid(struct drm_bridge *bridge,
- const struct drm_display_info *info,
- const struct drm_display_mode *mode)
- {
- switch (venc_get_videomode(mode)) {
- case VENC_MODE_PAL:
- case VENC_MODE_NTSC:
- return MODE_OK;
- default:
- return MODE_BAD;
- }
- }
- static bool venc_bridge_mode_fixup(struct drm_bridge *bridge,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
- {
- const struct drm_display_mode *venc_mode;
- switch (venc_get_videomode(adjusted_mode)) {
- case VENC_MODE_PAL:
- venc_mode = &omap_dss_pal_mode;
- break;
- case VENC_MODE_NTSC:
- venc_mode = &omap_dss_ntsc_mode;
- break;
- default:
- return false;
- }
- drm_mode_copy(adjusted_mode, venc_mode);
- drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
- drm_mode_set_name(adjusted_mode);
- return true;
- }
- static void venc_bridge_mode_set(struct drm_bridge *bridge,
- const struct drm_display_mode *mode,
- const struct drm_display_mode *adjusted_mode)
- {
- struct venc_device *venc = drm_bridge_to_venc(bridge);
- enum venc_videomode venc_mode = venc_get_videomode(adjusted_mode);
- switch (venc_mode) {
- default:
- WARN_ON_ONCE(1);
- fallthrough;
- case VENC_MODE_PAL:
- venc->config = &venc_config_pal_trm;
- break;
- case VENC_MODE_NTSC:
- venc->config = &venc_config_ntsc_trm;
- break;
- }
- dispc_set_tv_pclk(venc->dss->dispc, 13500000);
- }
- static void venc_bridge_enable(struct drm_bridge *bridge)
- {
- struct venc_device *venc = drm_bridge_to_venc(bridge);
- venc_power_on(venc);
- }
- static void venc_bridge_disable(struct drm_bridge *bridge)
- {
- struct venc_device *venc = drm_bridge_to_venc(bridge);
- venc_power_off(venc);
- }
- static int venc_bridge_get_modes(struct drm_bridge *bridge,
- struct drm_connector *connector)
- {
- static const struct drm_display_mode *modes[] = {
- &omap_dss_pal_mode,
- &omap_dss_ntsc_mode,
- };
- unsigned int i;
- for (i = 0; i < ARRAY_SIZE(modes); ++i) {
- struct drm_display_mode *mode;
- mode = drm_mode_duplicate(connector->dev, modes[i]);
- if (!mode)
- return i;
- mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
- drm_mode_set_name(mode);
- drm_mode_probed_add(connector, mode);
- }
- return ARRAY_SIZE(modes);
- }
- static const struct drm_bridge_funcs venc_bridge_funcs = {
- .attach = venc_bridge_attach,
- .mode_valid = venc_bridge_mode_valid,
- .mode_fixup = venc_bridge_mode_fixup,
- .mode_set = venc_bridge_mode_set,
- .enable = venc_bridge_enable,
- .disable = venc_bridge_disable,
- .get_modes = venc_bridge_get_modes,
- };
- static void venc_bridge_init(struct venc_device *venc)
- {
- venc->bridge.funcs = &venc_bridge_funcs;
- venc->bridge.of_node = venc->pdev->dev.of_node;
- venc->bridge.ops = DRM_BRIDGE_OP_MODES;
- venc->bridge.type = DRM_MODE_CONNECTOR_SVIDEO;
- venc->bridge.interlace_allowed = true;
- drm_bridge_add(&venc->bridge);
- }
- static void venc_bridge_cleanup(struct venc_device *venc)
- {
- drm_bridge_remove(&venc->bridge);
- }
- /* -----------------------------------------------------------------------------
- * Component Bind & Unbind
- */
- static int venc_bind(struct device *dev, struct device *master, void *data)
- {
- struct dss_device *dss = dss_get_device(master);
- struct venc_device *venc = dev_get_drvdata(dev);
- u8 rev_id;
- int r;
- venc->dss = dss;
- r = venc_runtime_get(venc);
- if (r)
- return r;
- rev_id = (u8)(venc_read_reg(venc, VENC_REV_ID) & 0xff);
- dev_dbg(dev, "OMAP VENC rev %d\n", rev_id);
- venc_runtime_put(venc);
- venc->debugfs = dss_debugfs_create_file(dss, "venc", venc_dump_regs,
- venc);
- return 0;
- }
- static void venc_unbind(struct device *dev, struct device *master, void *data)
- {
- struct venc_device *venc = dev_get_drvdata(dev);
- dss_debugfs_remove_file(venc->debugfs);
- }
- static const struct component_ops venc_component_ops = {
- .bind = venc_bind,
- .unbind = venc_unbind,
- };
- /* -----------------------------------------------------------------------------
- * Probe & Remove, Suspend & Resume
- */
- static int venc_init_output(struct venc_device *venc)
- {
- struct omap_dss_device *out = &venc->output;
- int r;
- venc_bridge_init(venc);
- out->dev = &venc->pdev->dev;
- out->id = OMAP_DSS_OUTPUT_VENC;
- out->type = OMAP_DISPLAY_TYPE_VENC;
- out->name = "venc.0";
- out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
- out->of_port = 0;
- r = omapdss_device_init_output(out, &venc->bridge);
- if (r < 0) {
- venc_bridge_cleanup(venc);
- return r;
- }
- omapdss_device_register(out);
- return 0;
- }
- static void venc_uninit_output(struct venc_device *venc)
- {
- omapdss_device_unregister(&venc->output);
- omapdss_device_cleanup_output(&venc->output);
- venc_bridge_cleanup(venc);
- }
- static int venc_probe_of(struct venc_device *venc)
- {
- struct device_node *node = venc->pdev->dev.of_node;
- struct device_node *ep;
- u32 channels;
- int r;
- ep = of_graph_get_endpoint_by_regs(node, 0, 0);
- if (!ep)
- return 0;
- venc->invert_polarity = of_property_read_bool(ep, "ti,invert-polarity");
- r = of_property_read_u32(ep, "ti,channels", &channels);
- if (r) {
- dev_err(&venc->pdev->dev,
- "failed to read property 'ti,channels': %d\n", r);
- goto err;
- }
- switch (channels) {
- case 1:
- venc->type = OMAP_DSS_VENC_TYPE_COMPOSITE;
- break;
- case 2:
- venc->type = OMAP_DSS_VENC_TYPE_SVIDEO;
- break;
- default:
- dev_err(&venc->pdev->dev, "bad channel property '%d'\n",
- channels);
- r = -EINVAL;
- goto err;
- }
- of_node_put(ep);
- return 0;
- err:
- of_node_put(ep);
- return r;
- }
- static const struct soc_device_attribute venc_soc_devices[] = {
- { .machine = "OMAP3[45]*" },
- { .machine = "AM35*" },
- { /* sentinel */ }
- };
- static int venc_probe(struct platform_device *pdev)
- {
- struct venc_device *venc;
- int r;
- venc = kzalloc(sizeof(*venc), GFP_KERNEL);
- if (!venc)
- return -ENOMEM;
- venc->pdev = pdev;
- platform_set_drvdata(pdev, venc);
- /* The OMAP34xx, OMAP35xx and AM35xx VENC require the TV DAC clock. */
- if (soc_device_match(venc_soc_devices))
- venc->requires_tv_dac_clk = true;
- venc->config = &venc_config_pal_trm;
- venc->base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(venc->base)) {
- r = PTR_ERR(venc->base);
- goto err_free;
- }
- venc->vdda_dac_reg = devm_regulator_get(&pdev->dev, "vdda");
- if (IS_ERR(venc->vdda_dac_reg)) {
- r = PTR_ERR(venc->vdda_dac_reg);
- if (r != -EPROBE_DEFER)
- DSSERR("can't get VDDA_DAC regulator\n");
- goto err_free;
- }
- r = venc_get_clocks(venc);
- if (r)
- goto err_free;
- r = venc_probe_of(venc);
- if (r)
- goto err_free;
- pm_runtime_enable(&pdev->dev);
- r = venc_init_output(venc);
- if (r)
- goto err_pm_disable;
- r = component_add(&pdev->dev, &venc_component_ops);
- if (r)
- goto err_uninit_output;
- return 0;
- err_uninit_output:
- venc_uninit_output(venc);
- err_pm_disable:
- pm_runtime_disable(&pdev->dev);
- err_free:
- kfree(venc);
- return r;
- }
- static int venc_remove(struct platform_device *pdev)
- {
- struct venc_device *venc = platform_get_drvdata(pdev);
- component_del(&pdev->dev, &venc_component_ops);
- venc_uninit_output(venc);
- pm_runtime_disable(&pdev->dev);
- kfree(venc);
- return 0;
- }
- static __maybe_unused int venc_runtime_suspend(struct device *dev)
- {
- struct venc_device *venc = dev_get_drvdata(dev);
- if (venc->tv_dac_clk)
- clk_disable_unprepare(venc->tv_dac_clk);
- return 0;
- }
- static __maybe_unused int venc_runtime_resume(struct device *dev)
- {
- struct venc_device *venc = dev_get_drvdata(dev);
- if (venc->tv_dac_clk)
- clk_prepare_enable(venc->tv_dac_clk);
- return 0;
- }
- static const struct dev_pm_ops venc_pm_ops = {
- SET_RUNTIME_PM_OPS(venc_runtime_suspend, venc_runtime_resume, NULL)
- SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
- };
- static const struct of_device_id venc_of_match[] = {
- { .compatible = "ti,omap2-venc", },
- { .compatible = "ti,omap3-venc", },
- { .compatible = "ti,omap4-venc", },
- {},
- };
- struct platform_driver omap_venchw_driver = {
- .probe = venc_probe,
- .remove = venc_remove,
- .driver = {
- .name = "omapdss_venc",
- .pm = &venc_pm_ops,
- .of_match_table = venc_of_match,
- .suppress_bind_attrs = true,
- },
- };
|