cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

vc4_vec.c (17536B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2016 Broadcom
      4 */
      5
      6/**
      7 * DOC: VC4 SDTV module
      8 *
      9 * The VEC encoder generates PAL or NTSC composite video output.
     10 *
     11 * TV mode selection is done by an atomic property on the encoder,
     12 * because a drm_mode_modeinfo is insufficient to distinguish between
     13 * PAL and PAL-M or NTSC and NTSC-J.
     14 */
     15
     16#include <drm/drm_atomic_helper.h>
     17#include <drm/drm_edid.h>
     18#include <drm/drm_panel.h>
     19#include <drm/drm_probe_helper.h>
     20#include <drm/drm_simple_kms_helper.h>
     21#include <linux/clk.h>
     22#include <linux/component.h>
     23#include <linux/of_graph.h>
     24#include <linux/of_platform.h>
     25#include <linux/pm_runtime.h>
     26
     27#include "vc4_drv.h"
     28#include "vc4_regs.h"
     29
     30/* WSE Registers */
     31#define VEC_WSE_RESET			0xc0
     32
     33#define VEC_WSE_CONTROL			0xc4
     34#define VEC_WSE_WSS_ENABLE		BIT(7)
     35
     36#define VEC_WSE_WSS_DATA		0xc8
     37#define VEC_WSE_VPS_DATA1		0xcc
     38#define VEC_WSE_VPS_CONTROL		0xd0
     39
     40/* VEC Registers */
     41#define VEC_REVID			0x100
     42
     43#define VEC_CONFIG0			0x104
     44#define VEC_CONFIG0_YDEL_MASK		GENMASK(28, 26)
     45#define VEC_CONFIG0_YDEL(x)		((x) << 26)
     46#define VEC_CONFIG0_CDEL_MASK		GENMASK(25, 24)
     47#define VEC_CONFIG0_CDEL(x)		((x) << 24)
     48#define VEC_CONFIG0_PBPR_FIL		BIT(18)
     49#define VEC_CONFIG0_CHROMA_GAIN_MASK	GENMASK(17, 16)
     50#define VEC_CONFIG0_CHROMA_GAIN_UNITY	(0 << 16)
     51#define VEC_CONFIG0_CHROMA_GAIN_1_32	(1 << 16)
     52#define VEC_CONFIG0_CHROMA_GAIN_1_16	(2 << 16)
     53#define VEC_CONFIG0_CHROMA_GAIN_1_8	(3 << 16)
     54#define VEC_CONFIG0_CBURST_GAIN_MASK	GENMASK(14, 13)
     55#define VEC_CONFIG0_CBURST_GAIN_UNITY	(0 << 13)
     56#define VEC_CONFIG0_CBURST_GAIN_1_128	(1 << 13)
     57#define VEC_CONFIG0_CBURST_GAIN_1_64	(2 << 13)
     58#define VEC_CONFIG0_CBURST_GAIN_1_32	(3 << 13)
     59#define VEC_CONFIG0_CHRBW1		BIT(11)
     60#define VEC_CONFIG0_CHRBW0		BIT(10)
     61#define VEC_CONFIG0_SYNCDIS		BIT(9)
     62#define VEC_CONFIG0_BURDIS		BIT(8)
     63#define VEC_CONFIG0_CHRDIS		BIT(7)
     64#define VEC_CONFIG0_PDEN		BIT(6)
     65#define VEC_CONFIG0_YCDELAY		BIT(4)
     66#define VEC_CONFIG0_RAMPEN		BIT(2)
     67#define VEC_CONFIG0_YCDIS		BIT(2)
     68#define VEC_CONFIG0_STD_MASK		GENMASK(1, 0)
     69#define VEC_CONFIG0_NTSC_STD		0
     70#define VEC_CONFIG0_PAL_BDGHI_STD	1
     71#define VEC_CONFIG0_PAL_N_STD		3
     72
     73#define VEC_SCHPH			0x108
     74#define VEC_SOFT_RESET			0x10c
     75#define VEC_CLMP0_START			0x144
     76#define VEC_CLMP0_END			0x148
     77#define VEC_FREQ3_2			0x180
     78#define VEC_FREQ1_0			0x184
     79
     80#define VEC_CONFIG1			0x188
     81#define VEC_CONFIG_VEC_RESYNC_OFF	BIT(18)
     82#define VEC_CONFIG_RGB219		BIT(17)
     83#define VEC_CONFIG_CBAR_EN		BIT(16)
     84#define VEC_CONFIG_TC_OBB		BIT(15)
     85#define VEC_CONFIG1_OUTPUT_MODE_MASK	GENMASK(12, 10)
     86#define VEC_CONFIG1_C_Y_CVBS		(0 << 10)
     87#define VEC_CONFIG1_CVBS_Y_C		(1 << 10)
     88#define VEC_CONFIG1_PR_Y_PB		(2 << 10)
     89#define VEC_CONFIG1_RGB			(4 << 10)
     90#define VEC_CONFIG1_Y_C_CVBS		(5 << 10)
     91#define VEC_CONFIG1_C_CVBS_Y		(6 << 10)
     92#define VEC_CONFIG1_C_CVBS_CVBS		(7 << 10)
     93#define VEC_CONFIG1_DIS_CHR		BIT(9)
     94#define VEC_CONFIG1_DIS_LUMA		BIT(8)
     95#define VEC_CONFIG1_YCBCR_IN		BIT(6)
     96#define VEC_CONFIG1_DITHER_TYPE_LFSR	0
     97#define VEC_CONFIG1_DITHER_TYPE_COUNTER	BIT(5)
     98#define VEC_CONFIG1_DITHER_EN		BIT(4)
     99#define VEC_CONFIG1_CYDELAY		BIT(3)
    100#define VEC_CONFIG1_LUMADIS		BIT(2)
    101#define VEC_CONFIG1_COMPDIS		BIT(1)
    102#define VEC_CONFIG1_CUSTOM_FREQ		BIT(0)
    103
    104#define VEC_CONFIG2			0x18c
    105#define VEC_CONFIG2_PROG_SCAN		BIT(15)
    106#define VEC_CONFIG2_SYNC_ADJ_MASK	GENMASK(14, 12)
    107#define VEC_CONFIG2_SYNC_ADJ(x)		(((x) / 2) << 12)
    108#define VEC_CONFIG2_PBPR_EN		BIT(10)
    109#define VEC_CONFIG2_UV_DIG_DIS		BIT(6)
    110#define VEC_CONFIG2_RGB_DIG_DIS		BIT(5)
    111#define VEC_CONFIG2_TMUX_MASK		GENMASK(3, 2)
    112#define VEC_CONFIG2_TMUX_DRIVE0		(0 << 2)
    113#define VEC_CONFIG2_TMUX_RG_COMP	(1 << 2)
    114#define VEC_CONFIG2_TMUX_UV_YC		(2 << 2)
    115#define VEC_CONFIG2_TMUX_SYNC_YC	(3 << 2)
    116
    117#define VEC_INTERRUPT_CONTROL		0x190
    118#define VEC_INTERRUPT_STATUS		0x194
    119#define VEC_FCW_SECAM_B			0x198
    120#define VEC_SECAM_GAIN_VAL		0x19c
    121
    122#define VEC_CONFIG3			0x1a0
    123#define VEC_CONFIG3_HORIZ_LEN_STD	(0 << 0)
    124#define VEC_CONFIG3_HORIZ_LEN_MPEG1_SIF	(1 << 0)
    125#define VEC_CONFIG3_SHAPE_NON_LINEAR	BIT(1)
    126
    127#define VEC_STATUS0			0x200
    128#define VEC_MASK0			0x204
    129
    130#define VEC_CFG				0x208
    131#define VEC_CFG_SG_MODE_MASK		GENMASK(6, 5)
    132#define VEC_CFG_SG_MODE(x)		((x) << 5)
    133#define VEC_CFG_SG_EN			BIT(4)
    134#define VEC_CFG_VEC_EN			BIT(3)
    135#define VEC_CFG_MB_EN			BIT(2)
    136#define VEC_CFG_ENABLE			BIT(1)
    137#define VEC_CFG_TB_EN			BIT(0)
    138
    139#define VEC_DAC_TEST			0x20c
    140
    141#define VEC_DAC_CONFIG			0x210
    142#define VEC_DAC_CONFIG_LDO_BIAS_CTRL(x)	((x) << 24)
    143#define VEC_DAC_CONFIG_DRIVER_CTRL(x)	((x) << 16)
    144#define VEC_DAC_CONFIG_DAC_CTRL(x)	(x)
    145
    146#define VEC_DAC_MISC			0x214
    147#define VEC_DAC_MISC_VCD_CTRL_MASK	GENMASK(31, 16)
    148#define VEC_DAC_MISC_VCD_CTRL(x)	((x) << 16)
    149#define VEC_DAC_MISC_VID_ACT		BIT(8)
    150#define VEC_DAC_MISC_VCD_PWRDN		BIT(6)
    151#define VEC_DAC_MISC_BIAS_PWRDN		BIT(5)
    152#define VEC_DAC_MISC_DAC_PWRDN		BIT(2)
    153#define VEC_DAC_MISC_LDO_PWRDN		BIT(1)
    154#define VEC_DAC_MISC_DAC_RST_N		BIT(0)
    155
    156
    157struct vc4_vec_variant {
    158	u32 dac_config;
    159};
    160
    161/* General VEC hardware state. */
    162struct vc4_vec {
    163	struct platform_device *pdev;
    164	const struct vc4_vec_variant *variant;
    165
    166	struct drm_encoder *encoder;
    167	struct drm_connector *connector;
    168
    169	void __iomem *regs;
    170
    171	struct clk *clock;
    172
    173	const struct vc4_vec_tv_mode *tv_mode;
    174
    175	struct debugfs_regset32 regset;
    176};
    177
    178#define VEC_READ(offset) readl(vec->regs + (offset))
    179#define VEC_WRITE(offset, val) writel(val, vec->regs + (offset))
    180
    181/* VC4 VEC encoder KMS struct */
    182struct vc4_vec_encoder {
    183	struct vc4_encoder base;
    184	struct vc4_vec *vec;
    185};
    186
    187static inline struct vc4_vec_encoder *
    188to_vc4_vec_encoder(struct drm_encoder *encoder)
    189{
    190	return container_of(encoder, struct vc4_vec_encoder, base.base);
    191}
    192
    193/* VC4 VEC connector KMS struct */
    194struct vc4_vec_connector {
    195	struct drm_connector base;
    196	struct vc4_vec *vec;
    197
    198	/* Since the connector is attached to just the one encoder,
    199	 * this is the reference to it so we can do the best_encoder()
    200	 * hook.
    201	 */
    202	struct drm_encoder *encoder;
    203};
    204
    205enum vc4_vec_tv_mode_id {
    206	VC4_VEC_TV_MODE_NTSC,
    207	VC4_VEC_TV_MODE_NTSC_J,
    208	VC4_VEC_TV_MODE_PAL,
    209	VC4_VEC_TV_MODE_PAL_M,
    210};
    211
    212struct vc4_vec_tv_mode {
    213	const struct drm_display_mode *mode;
    214	void (*mode_set)(struct vc4_vec *vec);
    215};
    216
    217static const struct debugfs_reg32 vec_regs[] = {
    218	VC4_REG32(VEC_WSE_CONTROL),
    219	VC4_REG32(VEC_WSE_WSS_DATA),
    220	VC4_REG32(VEC_WSE_VPS_DATA1),
    221	VC4_REG32(VEC_WSE_VPS_CONTROL),
    222	VC4_REG32(VEC_REVID),
    223	VC4_REG32(VEC_CONFIG0),
    224	VC4_REG32(VEC_SCHPH),
    225	VC4_REG32(VEC_CLMP0_START),
    226	VC4_REG32(VEC_CLMP0_END),
    227	VC4_REG32(VEC_FREQ3_2),
    228	VC4_REG32(VEC_FREQ1_0),
    229	VC4_REG32(VEC_CONFIG1),
    230	VC4_REG32(VEC_CONFIG2),
    231	VC4_REG32(VEC_INTERRUPT_CONTROL),
    232	VC4_REG32(VEC_INTERRUPT_STATUS),
    233	VC4_REG32(VEC_FCW_SECAM_B),
    234	VC4_REG32(VEC_SECAM_GAIN_VAL),
    235	VC4_REG32(VEC_CONFIG3),
    236	VC4_REG32(VEC_STATUS0),
    237	VC4_REG32(VEC_MASK0),
    238	VC4_REG32(VEC_CFG),
    239	VC4_REG32(VEC_DAC_TEST),
    240	VC4_REG32(VEC_DAC_CONFIG),
    241	VC4_REG32(VEC_DAC_MISC),
    242};
    243
    244static void vc4_vec_ntsc_mode_set(struct vc4_vec *vec)
    245{
    246	VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_NTSC_STD | VEC_CONFIG0_PDEN);
    247	VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS);
    248}
    249
    250static void vc4_vec_ntsc_j_mode_set(struct vc4_vec *vec)
    251{
    252	VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_NTSC_STD);
    253	VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS);
    254}
    255
    256static const struct drm_display_mode ntsc_mode = {
    257	DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 13500,
    258		 720, 720 + 14, 720 + 14 + 64, 720 + 14 + 64 + 60, 0,
    259		 480, 480 + 3, 480 + 3 + 3, 480 + 3 + 3 + 16, 0,
    260		 DRM_MODE_FLAG_INTERLACE)
    261};
    262
    263static void vc4_vec_pal_mode_set(struct vc4_vec *vec)
    264{
    265	VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_PAL_BDGHI_STD);
    266	VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS);
    267}
    268
    269static void vc4_vec_pal_m_mode_set(struct vc4_vec *vec)
    270{
    271	VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_PAL_BDGHI_STD);
    272	VEC_WRITE(VEC_CONFIG1,
    273		  VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ);
    274	VEC_WRITE(VEC_FREQ3_2, 0x223b);
    275	VEC_WRITE(VEC_FREQ1_0, 0x61d1);
    276}
    277
    278static const struct drm_display_mode pal_mode = {
    279	DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 13500,
    280		 720, 720 + 20, 720 + 20 + 64, 720 + 20 + 64 + 60, 0,
    281		 576, 576 + 2, 576 + 2 + 3, 576 + 2 + 3 + 20, 0,
    282		 DRM_MODE_FLAG_INTERLACE)
    283};
    284
    285static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = {
    286	[VC4_VEC_TV_MODE_NTSC] = {
    287		.mode = &ntsc_mode,
    288		.mode_set = vc4_vec_ntsc_mode_set,
    289	},
    290	[VC4_VEC_TV_MODE_NTSC_J] = {
    291		.mode = &ntsc_mode,
    292		.mode_set = vc4_vec_ntsc_j_mode_set,
    293	},
    294	[VC4_VEC_TV_MODE_PAL] = {
    295		.mode = &pal_mode,
    296		.mode_set = vc4_vec_pal_mode_set,
    297	},
    298	[VC4_VEC_TV_MODE_PAL_M] = {
    299		.mode = &pal_mode,
    300		.mode_set = vc4_vec_pal_m_mode_set,
    301	},
    302};
    303
    304static enum drm_connector_status
    305vc4_vec_connector_detect(struct drm_connector *connector, bool force)
    306{
    307	return connector_status_unknown;
    308}
    309
    310static void vc4_vec_connector_destroy(struct drm_connector *connector)
    311{
    312	drm_connector_unregister(connector);
    313	drm_connector_cleanup(connector);
    314}
    315
    316static int vc4_vec_connector_get_modes(struct drm_connector *connector)
    317{
    318	struct drm_connector_state *state = connector->state;
    319	struct drm_display_mode *mode;
    320
    321	mode = drm_mode_duplicate(connector->dev,
    322				  vc4_vec_tv_modes[state->tv.mode].mode);
    323	if (!mode) {
    324		DRM_ERROR("Failed to create a new display mode\n");
    325		return -ENOMEM;
    326	}
    327
    328	drm_mode_probed_add(connector, mode);
    329
    330	return 1;
    331}
    332
    333static const struct drm_connector_funcs vc4_vec_connector_funcs = {
    334	.detect = vc4_vec_connector_detect,
    335	.fill_modes = drm_helper_probe_single_connector_modes,
    336	.destroy = vc4_vec_connector_destroy,
    337	.reset = drm_atomic_helper_connector_reset,
    338	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
    339	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
    340};
    341
    342static const struct drm_connector_helper_funcs vc4_vec_connector_helper_funcs = {
    343	.get_modes = vc4_vec_connector_get_modes,
    344};
    345
    346static struct drm_connector *vc4_vec_connector_init(struct drm_device *dev,
    347						    struct vc4_vec *vec)
    348{
    349	struct drm_connector *connector = NULL;
    350	struct vc4_vec_connector *vec_connector;
    351
    352	vec_connector = devm_kzalloc(dev->dev, sizeof(*vec_connector),
    353				     GFP_KERNEL);
    354	if (!vec_connector)
    355		return ERR_PTR(-ENOMEM);
    356
    357	connector = &vec_connector->base;
    358	connector->interlace_allowed = true;
    359
    360	vec_connector->encoder = vec->encoder;
    361	vec_connector->vec = vec;
    362
    363	drm_connector_init(dev, connector, &vc4_vec_connector_funcs,
    364			   DRM_MODE_CONNECTOR_Composite);
    365	drm_connector_helper_add(connector, &vc4_vec_connector_helper_funcs);
    366
    367	drm_object_attach_property(&connector->base,
    368				   dev->mode_config.tv_mode_property,
    369				   VC4_VEC_TV_MODE_NTSC);
    370	vec->tv_mode = &vc4_vec_tv_modes[VC4_VEC_TV_MODE_NTSC];
    371
    372	drm_connector_attach_encoder(connector, vec->encoder);
    373
    374	return connector;
    375}
    376
    377static void vc4_vec_encoder_disable(struct drm_encoder *encoder)
    378{
    379	struct vc4_vec_encoder *vc4_vec_encoder = to_vc4_vec_encoder(encoder);
    380	struct vc4_vec *vec = vc4_vec_encoder->vec;
    381	int ret;
    382
    383	VEC_WRITE(VEC_CFG, 0);
    384	VEC_WRITE(VEC_DAC_MISC,
    385		  VEC_DAC_MISC_VCD_PWRDN |
    386		  VEC_DAC_MISC_BIAS_PWRDN |
    387		  VEC_DAC_MISC_DAC_PWRDN |
    388		  VEC_DAC_MISC_LDO_PWRDN);
    389
    390	clk_disable_unprepare(vec->clock);
    391
    392	ret = pm_runtime_put(&vec->pdev->dev);
    393	if (ret < 0) {
    394		DRM_ERROR("Failed to release power domain: %d\n", ret);
    395		return;
    396	}
    397}
    398
    399static void vc4_vec_encoder_enable(struct drm_encoder *encoder)
    400{
    401	struct vc4_vec_encoder *vc4_vec_encoder = to_vc4_vec_encoder(encoder);
    402	struct vc4_vec *vec = vc4_vec_encoder->vec;
    403	int ret;
    404
    405	ret = pm_runtime_get_sync(&vec->pdev->dev);
    406	if (ret < 0) {
    407		DRM_ERROR("Failed to retain power domain: %d\n", ret);
    408		return;
    409	}
    410
    411	/*
    412	 * We need to set the clock rate each time we enable the encoder
    413	 * because there's a chance we share the same parent with the HDMI
    414	 * clock, and both drivers are requesting different rates.
    415	 * The good news is, these 2 encoders cannot be enabled at the same
    416	 * time, thus preventing incompatible rate requests.
    417	 */
    418	ret = clk_set_rate(vec->clock, 108000000);
    419	if (ret) {
    420		DRM_ERROR("Failed to set clock rate: %d\n", ret);
    421		return;
    422	}
    423
    424	ret = clk_prepare_enable(vec->clock);
    425	if (ret) {
    426		DRM_ERROR("Failed to turn on core clock: %d\n", ret);
    427		return;
    428	}
    429
    430	/* Reset the different blocks */
    431	VEC_WRITE(VEC_WSE_RESET, 1);
    432	VEC_WRITE(VEC_SOFT_RESET, 1);
    433
    434	/* Disable the CGSM-A and WSE blocks */
    435	VEC_WRITE(VEC_WSE_CONTROL, 0);
    436
    437	/* Write config common to all modes. */
    438
    439	/*
    440	 * Color subcarrier phase: phase = 360 * SCHPH / 256.
    441	 * 0x28 <=> 39.375 deg.
    442	 */
    443	VEC_WRITE(VEC_SCHPH, 0x28);
    444
    445	/*
    446	 * Reset to default values.
    447	 */
    448	VEC_WRITE(VEC_CLMP0_START, 0xac);
    449	VEC_WRITE(VEC_CLMP0_END, 0xec);
    450	VEC_WRITE(VEC_CONFIG2,
    451		  VEC_CONFIG2_UV_DIG_DIS | VEC_CONFIG2_RGB_DIG_DIS);
    452	VEC_WRITE(VEC_CONFIG3, VEC_CONFIG3_HORIZ_LEN_STD);
    453	VEC_WRITE(VEC_DAC_CONFIG, vec->variant->dac_config);
    454
    455	/* Mask all interrupts. */
    456	VEC_WRITE(VEC_MASK0, 0);
    457
    458	vec->tv_mode->mode_set(vec);
    459
    460	VEC_WRITE(VEC_DAC_MISC,
    461		  VEC_DAC_MISC_VID_ACT | VEC_DAC_MISC_DAC_RST_N);
    462	VEC_WRITE(VEC_CFG, VEC_CFG_VEC_EN);
    463}
    464
    465
    466static bool vc4_vec_encoder_mode_fixup(struct drm_encoder *encoder,
    467				       const struct drm_display_mode *mode,
    468				       struct drm_display_mode *adjusted_mode)
    469{
    470	return true;
    471}
    472
    473static void vc4_vec_encoder_atomic_mode_set(struct drm_encoder *encoder,
    474					struct drm_crtc_state *crtc_state,
    475					struct drm_connector_state *conn_state)
    476{
    477	struct vc4_vec_encoder *vc4_vec_encoder = to_vc4_vec_encoder(encoder);
    478	struct vc4_vec *vec = vc4_vec_encoder->vec;
    479
    480	vec->tv_mode = &vc4_vec_tv_modes[conn_state->tv.mode];
    481}
    482
    483static int vc4_vec_encoder_atomic_check(struct drm_encoder *encoder,
    484					struct drm_crtc_state *crtc_state,
    485					struct drm_connector_state *conn_state)
    486{
    487	const struct vc4_vec_tv_mode *vec_mode;
    488
    489	vec_mode = &vc4_vec_tv_modes[conn_state->tv.mode];
    490
    491	if (conn_state->crtc &&
    492	    !drm_mode_equal(vec_mode->mode, &crtc_state->adjusted_mode))
    493		return -EINVAL;
    494
    495	return 0;
    496}
    497
    498static const struct drm_encoder_helper_funcs vc4_vec_encoder_helper_funcs = {
    499	.disable = vc4_vec_encoder_disable,
    500	.enable = vc4_vec_encoder_enable,
    501	.mode_fixup = vc4_vec_encoder_mode_fixup,
    502	.atomic_check = vc4_vec_encoder_atomic_check,
    503	.atomic_mode_set = vc4_vec_encoder_atomic_mode_set,
    504};
    505
    506static const struct vc4_vec_variant bcm2835_vec_variant = {
    507	.dac_config = VEC_DAC_CONFIG_DAC_CTRL(0xc) |
    508		      VEC_DAC_CONFIG_DRIVER_CTRL(0xc) |
    509		      VEC_DAC_CONFIG_LDO_BIAS_CTRL(0x46)
    510};
    511
    512static const struct vc4_vec_variant bcm2711_vec_variant = {
    513	.dac_config = VEC_DAC_CONFIG_DAC_CTRL(0x0) |
    514		      VEC_DAC_CONFIG_DRIVER_CTRL(0x80) |
    515		      VEC_DAC_CONFIG_LDO_BIAS_CTRL(0x61)
    516};
    517
    518static const struct of_device_id vc4_vec_dt_match[] = {
    519	{ .compatible = "brcm,bcm2835-vec", .data = &bcm2835_vec_variant },
    520	{ .compatible = "brcm,bcm2711-vec", .data = &bcm2711_vec_variant },
    521	{ /* sentinel */ },
    522};
    523
    524static const char * const tv_mode_names[] = {
    525	[VC4_VEC_TV_MODE_NTSC] = "NTSC",
    526	[VC4_VEC_TV_MODE_NTSC_J] = "NTSC-J",
    527	[VC4_VEC_TV_MODE_PAL] = "PAL",
    528	[VC4_VEC_TV_MODE_PAL_M] = "PAL-M",
    529};
    530
    531static int vc4_vec_bind(struct device *dev, struct device *master, void *data)
    532{
    533	struct platform_device *pdev = to_platform_device(dev);
    534	struct drm_device *drm = dev_get_drvdata(master);
    535	struct vc4_dev *vc4 = to_vc4_dev(drm);
    536	struct vc4_vec *vec;
    537	struct vc4_vec_encoder *vc4_vec_encoder;
    538	int ret;
    539
    540	ret = drm_mode_create_tv_properties(drm, ARRAY_SIZE(tv_mode_names),
    541					    tv_mode_names);
    542	if (ret)
    543		return ret;
    544
    545	vec = devm_kzalloc(dev, sizeof(*vec), GFP_KERNEL);
    546	if (!vec)
    547		return -ENOMEM;
    548
    549	vc4_vec_encoder = devm_kzalloc(dev, sizeof(*vc4_vec_encoder),
    550				       GFP_KERNEL);
    551	if (!vc4_vec_encoder)
    552		return -ENOMEM;
    553	vc4_vec_encoder->base.type = VC4_ENCODER_TYPE_VEC;
    554	vc4_vec_encoder->vec = vec;
    555	vec->encoder = &vc4_vec_encoder->base.base;
    556
    557	vec->pdev = pdev;
    558	vec->variant = (const struct vc4_vec_variant *)
    559		of_device_get_match_data(dev);
    560	vec->regs = vc4_ioremap_regs(pdev, 0);
    561	if (IS_ERR(vec->regs))
    562		return PTR_ERR(vec->regs);
    563	vec->regset.base = vec->regs;
    564	vec->regset.regs = vec_regs;
    565	vec->regset.nregs = ARRAY_SIZE(vec_regs);
    566
    567	vec->clock = devm_clk_get(dev, NULL);
    568	if (IS_ERR(vec->clock)) {
    569		ret = PTR_ERR(vec->clock);
    570		if (ret != -EPROBE_DEFER)
    571			DRM_ERROR("Failed to get clock: %d\n", ret);
    572		return ret;
    573	}
    574
    575	pm_runtime_enable(dev);
    576
    577	drm_simple_encoder_init(drm, vec->encoder, DRM_MODE_ENCODER_TVDAC);
    578	drm_encoder_helper_add(vec->encoder, &vc4_vec_encoder_helper_funcs);
    579
    580	vec->connector = vc4_vec_connector_init(drm, vec);
    581	if (IS_ERR(vec->connector)) {
    582		ret = PTR_ERR(vec->connector);
    583		goto err_destroy_encoder;
    584	}
    585
    586	dev_set_drvdata(dev, vec);
    587
    588	vc4->vec = vec;
    589
    590	vc4_debugfs_add_regset32(drm, "vec_regs", &vec->regset);
    591
    592	return 0;
    593
    594err_destroy_encoder:
    595	drm_encoder_cleanup(vec->encoder);
    596	pm_runtime_disable(dev);
    597
    598	return ret;
    599}
    600
    601static void vc4_vec_unbind(struct device *dev, struct device *master,
    602			   void *data)
    603{
    604	struct drm_device *drm = dev_get_drvdata(master);
    605	struct vc4_dev *vc4 = to_vc4_dev(drm);
    606	struct vc4_vec *vec = dev_get_drvdata(dev);
    607
    608	vc4_vec_connector_destroy(vec->connector);
    609	drm_encoder_cleanup(vec->encoder);
    610	pm_runtime_disable(dev);
    611
    612	vc4->vec = NULL;
    613}
    614
    615static const struct component_ops vc4_vec_ops = {
    616	.bind   = vc4_vec_bind,
    617	.unbind = vc4_vec_unbind,
    618};
    619
    620static int vc4_vec_dev_probe(struct platform_device *pdev)
    621{
    622	return component_add(&pdev->dev, &vc4_vec_ops);
    623}
    624
    625static int vc4_vec_dev_remove(struct platform_device *pdev)
    626{
    627	component_del(&pdev->dev, &vc4_vec_ops);
    628	return 0;
    629}
    630
    631struct platform_driver vc4_vec_driver = {
    632	.probe = vc4_vec_dev_probe,
    633	.remove = vc4_vec_dev_remove,
    634	.driver = {
    635		.name = "vc4_vec",
    636		.of_match_table = vc4_vec_dt_match,
    637	},
    638};