1cdfbff78SBenjamin Gaignard /* 2cdfbff78SBenjamin Gaignard * Copyright (C) STMicroelectronics SA 2014 3cdfbff78SBenjamin Gaignard * Authors: Benjamin Gaignard <benjamin.gaignard@st.com> 4cdfbff78SBenjamin Gaignard * Vincent Abriou <vincent.abriou@st.com> 5cdfbff78SBenjamin Gaignard * for STMicroelectronics. 6cdfbff78SBenjamin Gaignard * License terms: GNU General Public License (GPL), version 2 7cdfbff78SBenjamin Gaignard */ 8cdfbff78SBenjamin Gaignard 9cdfbff78SBenjamin Gaignard #include <linux/clk.h> 10cdfbff78SBenjamin Gaignard #include <linux/component.h> 11cdfbff78SBenjamin Gaignard #include <linux/module.h> 12cdfbff78SBenjamin Gaignard #include <linux/of_platform.h> 13cdfbff78SBenjamin Gaignard #include <linux/platform_device.h> 14cdfbff78SBenjamin Gaignard #include <linux/reset.h> 15cdfbff78SBenjamin Gaignard 16cdfbff78SBenjamin Gaignard #include <drm/drmP.h> 17cdfbff78SBenjamin Gaignard #include <drm/drm_crtc_helper.h> 18cdfbff78SBenjamin Gaignard 19cdfbff78SBenjamin Gaignard /* glue registers */ 20cdfbff78SBenjamin Gaignard #define TVO_CSC_MAIN_M0 0x000 21cdfbff78SBenjamin Gaignard #define TVO_CSC_MAIN_M1 0x004 22cdfbff78SBenjamin Gaignard #define TVO_CSC_MAIN_M2 0x008 23cdfbff78SBenjamin Gaignard #define TVO_CSC_MAIN_M3 0x00c 24cdfbff78SBenjamin Gaignard #define TVO_CSC_MAIN_M4 0x010 25cdfbff78SBenjamin Gaignard #define TVO_CSC_MAIN_M5 0x014 26cdfbff78SBenjamin Gaignard #define TVO_CSC_MAIN_M6 0x018 27cdfbff78SBenjamin Gaignard #define TVO_CSC_MAIN_M7 0x01c 28cdfbff78SBenjamin Gaignard #define TVO_MAIN_IN_VID_FORMAT 0x030 29cdfbff78SBenjamin Gaignard #define TVO_CSC_AUX_M0 0x100 30cdfbff78SBenjamin Gaignard #define TVO_CSC_AUX_M1 0x104 31cdfbff78SBenjamin Gaignard #define TVO_CSC_AUX_M2 0x108 32cdfbff78SBenjamin Gaignard #define TVO_CSC_AUX_M3 0x10c 33cdfbff78SBenjamin Gaignard #define TVO_CSC_AUX_M4 0x110 34cdfbff78SBenjamin Gaignard #define TVO_CSC_AUX_M5 0x114 35cdfbff78SBenjamin Gaignard #define TVO_CSC_AUX_M6 0x118 36cdfbff78SBenjamin Gaignard #define TVO_CSC_AUX_M7 0x11c 37cdfbff78SBenjamin Gaignard #define TVO_AUX_IN_VID_FORMAT 0x130 38cdfbff78SBenjamin Gaignard #define TVO_VIP_HDF 0x400 39cdfbff78SBenjamin Gaignard #define TVO_HD_SYNC_SEL 0x418 40cdfbff78SBenjamin Gaignard #define TVO_HD_DAC_CFG_OFF 0x420 41cdfbff78SBenjamin Gaignard #define TVO_VIP_HDMI 0x500 42cdfbff78SBenjamin Gaignard #define TVO_HDMI_FORCE_COLOR_0 0x504 43cdfbff78SBenjamin Gaignard #define TVO_HDMI_FORCE_COLOR_1 0x508 44cdfbff78SBenjamin Gaignard #define TVO_HDMI_CLIP_VALUE_B_CB 0x50c 45cdfbff78SBenjamin Gaignard #define TVO_HDMI_CLIP_VALUE_Y_G 0x510 46cdfbff78SBenjamin Gaignard #define TVO_HDMI_CLIP_VALUE_R_CR 0x514 47cdfbff78SBenjamin Gaignard #define TVO_HDMI_SYNC_SEL 0x518 48cdfbff78SBenjamin Gaignard #define TVO_HDMI_DFV_OBS 0x540 49cdfbff78SBenjamin Gaignard 50cdfbff78SBenjamin Gaignard #define TVO_IN_FMT_SIGNED BIT(0) 51cdfbff78SBenjamin Gaignard #define TVO_SYNC_EXT BIT(4) 52cdfbff78SBenjamin Gaignard 53cdfbff78SBenjamin Gaignard #define TVO_VIP_REORDER_R_SHIFT 24 54cdfbff78SBenjamin Gaignard #define TVO_VIP_REORDER_G_SHIFT 20 55cdfbff78SBenjamin Gaignard #define TVO_VIP_REORDER_B_SHIFT 16 56cdfbff78SBenjamin Gaignard #define TVO_VIP_REORDER_MASK 0x3 57cdfbff78SBenjamin Gaignard #define TVO_VIP_REORDER_Y_G_SEL 0 58cdfbff78SBenjamin Gaignard #define TVO_VIP_REORDER_CB_B_SEL 1 59cdfbff78SBenjamin Gaignard #define TVO_VIP_REORDER_CR_R_SEL 2 60cdfbff78SBenjamin Gaignard 61cdfbff78SBenjamin Gaignard #define TVO_VIP_CLIP_SHIFT 8 62cdfbff78SBenjamin Gaignard #define TVO_VIP_CLIP_MASK 0x7 63cdfbff78SBenjamin Gaignard #define TVO_VIP_CLIP_DISABLED 0 64cdfbff78SBenjamin Gaignard #define TVO_VIP_CLIP_EAV_SAV 1 65cdfbff78SBenjamin Gaignard #define TVO_VIP_CLIP_LIMITED_RANGE_RGB_Y 2 66cdfbff78SBenjamin Gaignard #define TVO_VIP_CLIP_LIMITED_RANGE_CB_CR 3 67cdfbff78SBenjamin Gaignard #define TVO_VIP_CLIP_PROG_RANGE 4 68cdfbff78SBenjamin Gaignard 69cdfbff78SBenjamin Gaignard #define TVO_VIP_RND_SHIFT 4 70cdfbff78SBenjamin Gaignard #define TVO_VIP_RND_MASK 0x3 71cdfbff78SBenjamin Gaignard #define TVO_VIP_RND_8BIT_ROUNDED 0 72cdfbff78SBenjamin Gaignard #define TVO_VIP_RND_10BIT_ROUNDED 1 73cdfbff78SBenjamin Gaignard #define TVO_VIP_RND_12BIT_ROUNDED 2 74cdfbff78SBenjamin Gaignard 75cdfbff78SBenjamin Gaignard #define TVO_VIP_SEL_INPUT_MASK 0xf 76cdfbff78SBenjamin Gaignard #define TVO_VIP_SEL_INPUT_MAIN 0x0 77cdfbff78SBenjamin Gaignard #define TVO_VIP_SEL_INPUT_AUX 0x8 78cdfbff78SBenjamin Gaignard #define TVO_VIP_SEL_INPUT_FORCE_COLOR 0xf 79cdfbff78SBenjamin Gaignard #define TVO_VIP_SEL_INPUT_BYPASS_MASK 0x1 80cdfbff78SBenjamin Gaignard #define TVO_VIP_SEL_INPUT_BYPASSED 1 81cdfbff78SBenjamin Gaignard 82cdfbff78SBenjamin Gaignard #define TVO_SYNC_MAIN_VTG_SET_REF 0x00 83cdfbff78SBenjamin Gaignard #define TVO_SYNC_MAIN_VTG_SET_1 0x01 84cdfbff78SBenjamin Gaignard #define TVO_SYNC_MAIN_VTG_SET_2 0x02 85cdfbff78SBenjamin Gaignard #define TVO_SYNC_MAIN_VTG_SET_3 0x03 86cdfbff78SBenjamin Gaignard #define TVO_SYNC_MAIN_VTG_SET_4 0x04 87cdfbff78SBenjamin Gaignard #define TVO_SYNC_MAIN_VTG_SET_5 0x05 88cdfbff78SBenjamin Gaignard #define TVO_SYNC_MAIN_VTG_SET_6 0x06 89cdfbff78SBenjamin Gaignard #define TVO_SYNC_AUX_VTG_SET_REF 0x10 90cdfbff78SBenjamin Gaignard #define TVO_SYNC_AUX_VTG_SET_1 0x11 91cdfbff78SBenjamin Gaignard #define TVO_SYNC_AUX_VTG_SET_2 0x12 92cdfbff78SBenjamin Gaignard #define TVO_SYNC_AUX_VTG_SET_3 0x13 93cdfbff78SBenjamin Gaignard #define TVO_SYNC_AUX_VTG_SET_4 0x14 94cdfbff78SBenjamin Gaignard #define TVO_SYNC_AUX_VTG_SET_5 0x15 95cdfbff78SBenjamin Gaignard #define TVO_SYNC_AUX_VTG_SET_6 0x16 96cdfbff78SBenjamin Gaignard 97cdfbff78SBenjamin Gaignard #define TVO_SYNC_HD_DCS_SHIFT 8 98cdfbff78SBenjamin Gaignard 99cdfbff78SBenjamin Gaignard #define ENCODER_MAIN_CRTC_MASK BIT(0) 100cdfbff78SBenjamin Gaignard 101cdfbff78SBenjamin Gaignard /* enum listing the supported output data format */ 102cdfbff78SBenjamin Gaignard enum sti_tvout_video_out_type { 103cdfbff78SBenjamin Gaignard STI_TVOUT_VIDEO_OUT_RGB, 104cdfbff78SBenjamin Gaignard STI_TVOUT_VIDEO_OUT_YUV, 105cdfbff78SBenjamin Gaignard }; 106cdfbff78SBenjamin Gaignard 107cdfbff78SBenjamin Gaignard struct sti_tvout { 108cdfbff78SBenjamin Gaignard struct device *dev; 109cdfbff78SBenjamin Gaignard struct drm_device *drm_dev; 110cdfbff78SBenjamin Gaignard void __iomem *regs; 111cdfbff78SBenjamin Gaignard struct reset_control *reset; 112cdfbff78SBenjamin Gaignard struct drm_encoder *hdmi; 113cdfbff78SBenjamin Gaignard struct drm_encoder *hda; 114cdfbff78SBenjamin Gaignard }; 115cdfbff78SBenjamin Gaignard 116cdfbff78SBenjamin Gaignard struct sti_tvout_encoder { 117cdfbff78SBenjamin Gaignard struct drm_encoder encoder; 118cdfbff78SBenjamin Gaignard struct sti_tvout *tvout; 119cdfbff78SBenjamin Gaignard }; 120cdfbff78SBenjamin Gaignard 121cdfbff78SBenjamin Gaignard #define to_sti_tvout_encoder(x) \ 122cdfbff78SBenjamin Gaignard container_of(x, struct sti_tvout_encoder, encoder) 123cdfbff78SBenjamin Gaignard 124cdfbff78SBenjamin Gaignard #define to_sti_tvout(x) to_sti_tvout_encoder(x)->tvout 125cdfbff78SBenjamin Gaignard 126cdfbff78SBenjamin Gaignard /* preformatter conversion matrix */ 127cdfbff78SBenjamin Gaignard static const u32 rgb_to_ycbcr_601[8] = { 128cdfbff78SBenjamin Gaignard 0xF927082E, 0x04C9FEAB, 0x01D30964, 0xFA95FD3D, 129cdfbff78SBenjamin Gaignard 0x0000082E, 0x00002000, 0x00002000, 0x00000000 130cdfbff78SBenjamin Gaignard }; 131cdfbff78SBenjamin Gaignard 132cdfbff78SBenjamin Gaignard /* 709 RGB to YCbCr */ 133cdfbff78SBenjamin Gaignard static const u32 rgb_to_ycbcr_709[8] = { 134cdfbff78SBenjamin Gaignard 0xF891082F, 0x0367FF40, 0x01280B71, 0xF9B1FE20, 135cdfbff78SBenjamin Gaignard 0x0000082F, 0x00002000, 0x00002000, 0x00000000 136cdfbff78SBenjamin Gaignard }; 137cdfbff78SBenjamin Gaignard 138cdfbff78SBenjamin Gaignard static u32 tvout_read(struct sti_tvout *tvout, int offset) 139cdfbff78SBenjamin Gaignard { 140cdfbff78SBenjamin Gaignard return readl(tvout->regs + offset); 141cdfbff78SBenjamin Gaignard } 142cdfbff78SBenjamin Gaignard 143cdfbff78SBenjamin Gaignard static void tvout_write(struct sti_tvout *tvout, u32 val, int offset) 144cdfbff78SBenjamin Gaignard { 145cdfbff78SBenjamin Gaignard writel(val, tvout->regs + offset); 146cdfbff78SBenjamin Gaignard } 147cdfbff78SBenjamin Gaignard 148cdfbff78SBenjamin Gaignard /** 149cdfbff78SBenjamin Gaignard * Set the clipping mode of a VIP 150cdfbff78SBenjamin Gaignard * 151cdfbff78SBenjamin Gaignard * @tvout: tvout structure 152cdfbff78SBenjamin Gaignard * @cr_r: 153cdfbff78SBenjamin Gaignard * @y_g: 154cdfbff78SBenjamin Gaignard * @cb_b: 155cdfbff78SBenjamin Gaignard */ 156cdfbff78SBenjamin Gaignard static void tvout_vip_set_color_order(struct sti_tvout *tvout, 157cdfbff78SBenjamin Gaignard u32 cr_r, u32 y_g, u32 cb_b) 158cdfbff78SBenjamin Gaignard { 159cdfbff78SBenjamin Gaignard u32 val = tvout_read(tvout, TVO_VIP_HDMI); 160cdfbff78SBenjamin Gaignard 161cdfbff78SBenjamin Gaignard val &= ~(TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_R_SHIFT); 162cdfbff78SBenjamin Gaignard val &= ~(TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_G_SHIFT); 163cdfbff78SBenjamin Gaignard val &= ~(TVO_VIP_REORDER_MASK << TVO_VIP_REORDER_B_SHIFT); 164cdfbff78SBenjamin Gaignard val |= cr_r << TVO_VIP_REORDER_R_SHIFT; 165cdfbff78SBenjamin Gaignard val |= y_g << TVO_VIP_REORDER_G_SHIFT; 166cdfbff78SBenjamin Gaignard val |= cb_b << TVO_VIP_REORDER_B_SHIFT; 167cdfbff78SBenjamin Gaignard 168cdfbff78SBenjamin Gaignard tvout_write(tvout, val, TVO_VIP_HDMI); 169cdfbff78SBenjamin Gaignard } 170cdfbff78SBenjamin Gaignard 171cdfbff78SBenjamin Gaignard /** 172cdfbff78SBenjamin Gaignard * Set the clipping mode of a VIP 173cdfbff78SBenjamin Gaignard * 174cdfbff78SBenjamin Gaignard * @tvout: tvout structure 175cdfbff78SBenjamin Gaignard * @range: clipping range 176cdfbff78SBenjamin Gaignard */ 177cdfbff78SBenjamin Gaignard static void tvout_vip_set_clip_mode(struct sti_tvout *tvout, u32 range) 178cdfbff78SBenjamin Gaignard { 179cdfbff78SBenjamin Gaignard u32 val = tvout_read(tvout, TVO_VIP_HDMI); 180cdfbff78SBenjamin Gaignard 181cdfbff78SBenjamin Gaignard val &= ~(TVO_VIP_CLIP_MASK << TVO_VIP_CLIP_SHIFT); 182cdfbff78SBenjamin Gaignard val |= range << TVO_VIP_CLIP_SHIFT; 183cdfbff78SBenjamin Gaignard tvout_write(tvout, val, TVO_VIP_HDMI); 184cdfbff78SBenjamin Gaignard } 185cdfbff78SBenjamin Gaignard 186cdfbff78SBenjamin Gaignard /** 187cdfbff78SBenjamin Gaignard * Set the rounded value of a VIP 188cdfbff78SBenjamin Gaignard * 189cdfbff78SBenjamin Gaignard * @tvout: tvout structure 190cdfbff78SBenjamin Gaignard * @rnd: rounded val per component 191cdfbff78SBenjamin Gaignard */ 192cdfbff78SBenjamin Gaignard static void tvout_vip_set_rnd(struct sti_tvout *tvout, u32 rnd) 193cdfbff78SBenjamin Gaignard { 194cdfbff78SBenjamin Gaignard u32 val = tvout_read(tvout, TVO_VIP_HDMI); 195cdfbff78SBenjamin Gaignard 196cdfbff78SBenjamin Gaignard val &= ~(TVO_VIP_RND_MASK << TVO_VIP_RND_SHIFT); 197cdfbff78SBenjamin Gaignard val |= rnd << TVO_VIP_RND_SHIFT; 198cdfbff78SBenjamin Gaignard tvout_write(tvout, val, TVO_VIP_HDMI); 199cdfbff78SBenjamin Gaignard } 200cdfbff78SBenjamin Gaignard 201cdfbff78SBenjamin Gaignard /** 202cdfbff78SBenjamin Gaignard * Select the VIP input 203cdfbff78SBenjamin Gaignard * 204cdfbff78SBenjamin Gaignard * @tvout: tvout structure 205cdfbff78SBenjamin Gaignard * @sel_input: selected_input (main/aux + conv) 206cdfbff78SBenjamin Gaignard */ 207cdfbff78SBenjamin Gaignard static void tvout_vip_set_sel_input(struct sti_tvout *tvout, 208cdfbff78SBenjamin Gaignard bool main_path, 209cdfbff78SBenjamin Gaignard bool sel_input_logic_inverted, 210cdfbff78SBenjamin Gaignard enum sti_tvout_video_out_type video_out) 211cdfbff78SBenjamin Gaignard { 212cdfbff78SBenjamin Gaignard u32 sel_input; 213cdfbff78SBenjamin Gaignard u32 val = tvout_read(tvout, TVO_VIP_HDMI); 214cdfbff78SBenjamin Gaignard 215cdfbff78SBenjamin Gaignard if (main_path) 216cdfbff78SBenjamin Gaignard sel_input = TVO_VIP_SEL_INPUT_MAIN; 217cdfbff78SBenjamin Gaignard else 218cdfbff78SBenjamin Gaignard sel_input = TVO_VIP_SEL_INPUT_AUX; 219cdfbff78SBenjamin Gaignard 220cdfbff78SBenjamin Gaignard switch (video_out) { 221cdfbff78SBenjamin Gaignard case STI_TVOUT_VIDEO_OUT_RGB: 222cdfbff78SBenjamin Gaignard sel_input |= TVO_VIP_SEL_INPUT_BYPASSED; 223cdfbff78SBenjamin Gaignard break; 224cdfbff78SBenjamin Gaignard case STI_TVOUT_VIDEO_OUT_YUV: 225cdfbff78SBenjamin Gaignard sel_input &= ~TVO_VIP_SEL_INPUT_BYPASSED; 226cdfbff78SBenjamin Gaignard break; 227cdfbff78SBenjamin Gaignard } 228cdfbff78SBenjamin Gaignard 229cdfbff78SBenjamin Gaignard /* on stih407 chip the sel_input bypass mode logic is inverted */ 230cdfbff78SBenjamin Gaignard if (sel_input_logic_inverted) 231cdfbff78SBenjamin Gaignard sel_input = sel_input ^ TVO_VIP_SEL_INPUT_BYPASS_MASK; 232cdfbff78SBenjamin Gaignard 233cdfbff78SBenjamin Gaignard val &= ~TVO_VIP_SEL_INPUT_MASK; 234cdfbff78SBenjamin Gaignard val |= sel_input; 235cdfbff78SBenjamin Gaignard tvout_write(tvout, val, TVO_VIP_HDMI); 236cdfbff78SBenjamin Gaignard } 237cdfbff78SBenjamin Gaignard 238cdfbff78SBenjamin Gaignard /** 239cdfbff78SBenjamin Gaignard * Select the input video signed or unsigned 240cdfbff78SBenjamin Gaignard * 241cdfbff78SBenjamin Gaignard * @tvout: tvout structure 242cdfbff78SBenjamin Gaignard * @in_vid_signed: used video input format 243cdfbff78SBenjamin Gaignard */ 244cdfbff78SBenjamin Gaignard static void tvout_vip_set_in_vid_fmt(struct sti_tvout *tvout, u32 in_vid_fmt) 245cdfbff78SBenjamin Gaignard { 246cdfbff78SBenjamin Gaignard u32 val = tvout_read(tvout, TVO_VIP_HDMI); 247cdfbff78SBenjamin Gaignard 248cdfbff78SBenjamin Gaignard val &= ~TVO_IN_FMT_SIGNED; 249cdfbff78SBenjamin Gaignard val |= in_vid_fmt; 250cdfbff78SBenjamin Gaignard tvout_write(tvout, val, TVO_MAIN_IN_VID_FORMAT); 251cdfbff78SBenjamin Gaignard } 252cdfbff78SBenjamin Gaignard 253cdfbff78SBenjamin Gaignard /** 254cdfbff78SBenjamin Gaignard * Start VIP block for HDMI output 255cdfbff78SBenjamin Gaignard * 256cdfbff78SBenjamin Gaignard * @tvout: pointer on tvout structure 257cdfbff78SBenjamin Gaignard * @main_path: true if main path has to be used in the vip configuration 258cdfbff78SBenjamin Gaignard * else aux path is used. 259cdfbff78SBenjamin Gaignard */ 260cdfbff78SBenjamin Gaignard static void tvout_hdmi_start(struct sti_tvout *tvout, bool main_path) 261cdfbff78SBenjamin Gaignard { 262cdfbff78SBenjamin Gaignard struct device_node *node = tvout->dev->of_node; 263cdfbff78SBenjamin Gaignard bool sel_input_logic_inverted = false; 264cdfbff78SBenjamin Gaignard 265cdfbff78SBenjamin Gaignard dev_dbg(tvout->dev, "%s\n", __func__); 266cdfbff78SBenjamin Gaignard 267cdfbff78SBenjamin Gaignard if (main_path) { 268cdfbff78SBenjamin Gaignard DRM_DEBUG_DRIVER("main vip for hdmi\n"); 269cdfbff78SBenjamin Gaignard /* select the input sync for hdmi = VTG set 1 */ 270cdfbff78SBenjamin Gaignard tvout_write(tvout, TVO_SYNC_MAIN_VTG_SET_1, TVO_HDMI_SYNC_SEL); 271cdfbff78SBenjamin Gaignard } else { 272cdfbff78SBenjamin Gaignard DRM_DEBUG_DRIVER("aux vip for hdmi\n"); 273cdfbff78SBenjamin Gaignard /* select the input sync for hdmi = VTG set 1 */ 274cdfbff78SBenjamin Gaignard tvout_write(tvout, TVO_SYNC_AUX_VTG_SET_1, TVO_HDMI_SYNC_SEL); 275cdfbff78SBenjamin Gaignard } 276cdfbff78SBenjamin Gaignard 277cdfbff78SBenjamin Gaignard /* set color channel order */ 278cdfbff78SBenjamin Gaignard tvout_vip_set_color_order(tvout, 279cdfbff78SBenjamin Gaignard TVO_VIP_REORDER_CR_R_SEL, 280cdfbff78SBenjamin Gaignard TVO_VIP_REORDER_Y_G_SEL, 281cdfbff78SBenjamin Gaignard TVO_VIP_REORDER_CB_B_SEL); 282cdfbff78SBenjamin Gaignard 283cdfbff78SBenjamin Gaignard /* set clipping mode (Limited range RGB/Y) */ 284cdfbff78SBenjamin Gaignard tvout_vip_set_clip_mode(tvout, TVO_VIP_CLIP_LIMITED_RANGE_RGB_Y); 285cdfbff78SBenjamin Gaignard 286cdfbff78SBenjamin Gaignard /* set round mode (rounded to 8-bit per component) */ 287cdfbff78SBenjamin Gaignard tvout_vip_set_rnd(tvout, TVO_VIP_RND_8BIT_ROUNDED); 288cdfbff78SBenjamin Gaignard 289cdfbff78SBenjamin Gaignard if (of_device_is_compatible(node, "st,stih407-tvout")) { 290cdfbff78SBenjamin Gaignard /* set input video format */ 291cdfbff78SBenjamin Gaignard tvout_vip_set_in_vid_fmt(tvout->regs + TVO_MAIN_IN_VID_FORMAT, 292cdfbff78SBenjamin Gaignard TVO_IN_FMT_SIGNED); 293cdfbff78SBenjamin Gaignard sel_input_logic_inverted = true; 294cdfbff78SBenjamin Gaignard } 295cdfbff78SBenjamin Gaignard 296cdfbff78SBenjamin Gaignard /* input selection */ 297cdfbff78SBenjamin Gaignard tvout_vip_set_sel_input(tvout, main_path, 298cdfbff78SBenjamin Gaignard sel_input_logic_inverted, STI_TVOUT_VIDEO_OUT_RGB); 299cdfbff78SBenjamin Gaignard } 300cdfbff78SBenjamin Gaignard 301cdfbff78SBenjamin Gaignard /** 302cdfbff78SBenjamin Gaignard * Start HDF VIP and HD DAC 303cdfbff78SBenjamin Gaignard * 304cdfbff78SBenjamin Gaignard * @tvout: pointer on tvout structure 305cdfbff78SBenjamin Gaignard * @main_path: true if main path has to be used in the vip configuration 306cdfbff78SBenjamin Gaignard * else aux path is used. 307cdfbff78SBenjamin Gaignard */ 308cdfbff78SBenjamin Gaignard static void tvout_hda_start(struct sti_tvout *tvout, bool main_path) 309cdfbff78SBenjamin Gaignard { 310cdfbff78SBenjamin Gaignard struct device_node *node = tvout->dev->of_node; 311cdfbff78SBenjamin Gaignard bool sel_input_logic_inverted = false; 312cdfbff78SBenjamin Gaignard 313cdfbff78SBenjamin Gaignard dev_dbg(tvout->dev, "%s\n", __func__); 314cdfbff78SBenjamin Gaignard 315cdfbff78SBenjamin Gaignard if (!main_path) { 316cdfbff78SBenjamin Gaignard DRM_ERROR("HD Analog on aux not implemented\n"); 317cdfbff78SBenjamin Gaignard return; 318cdfbff78SBenjamin Gaignard } 319cdfbff78SBenjamin Gaignard 320cdfbff78SBenjamin Gaignard DRM_DEBUG_DRIVER("main vip for HDF\n"); 321cdfbff78SBenjamin Gaignard 322cdfbff78SBenjamin Gaignard /* set color channel order */ 323cdfbff78SBenjamin Gaignard tvout_vip_set_color_order(tvout->regs + TVO_VIP_HDF, 324cdfbff78SBenjamin Gaignard TVO_VIP_REORDER_CR_R_SEL, 325cdfbff78SBenjamin Gaignard TVO_VIP_REORDER_Y_G_SEL, 326cdfbff78SBenjamin Gaignard TVO_VIP_REORDER_CB_B_SEL); 327cdfbff78SBenjamin Gaignard 328cdfbff78SBenjamin Gaignard /* set clipping mode (Limited range RGB/Y) */ 329cdfbff78SBenjamin Gaignard tvout_vip_set_clip_mode(tvout->regs + TVO_VIP_HDF, 330cdfbff78SBenjamin Gaignard TVO_VIP_CLIP_LIMITED_RANGE_CB_CR); 331cdfbff78SBenjamin Gaignard 332cdfbff78SBenjamin Gaignard /* set round mode (rounded to 10-bit per component) */ 333cdfbff78SBenjamin Gaignard tvout_vip_set_rnd(tvout->regs + TVO_VIP_HDF, TVO_VIP_RND_10BIT_ROUNDED); 334cdfbff78SBenjamin Gaignard 335cdfbff78SBenjamin Gaignard if (of_device_is_compatible(node, "st,stih407-tvout")) { 336cdfbff78SBenjamin Gaignard /* set input video format */ 337cdfbff78SBenjamin Gaignard tvout_vip_set_in_vid_fmt(tvout, TVO_IN_FMT_SIGNED); 338cdfbff78SBenjamin Gaignard sel_input_logic_inverted = true; 339cdfbff78SBenjamin Gaignard } 340cdfbff78SBenjamin Gaignard 341cdfbff78SBenjamin Gaignard /* Input selection */ 342cdfbff78SBenjamin Gaignard tvout_vip_set_sel_input(tvout->regs + TVO_VIP_HDF, 343cdfbff78SBenjamin Gaignard main_path, 344cdfbff78SBenjamin Gaignard sel_input_logic_inverted, 345cdfbff78SBenjamin Gaignard STI_TVOUT_VIDEO_OUT_YUV); 346cdfbff78SBenjamin Gaignard 347cdfbff78SBenjamin Gaignard /* select the input sync for HD analog = VTG set 3 348cdfbff78SBenjamin Gaignard * and HD DCS = VTG set 2 */ 349cdfbff78SBenjamin Gaignard tvout_write(tvout, 350cdfbff78SBenjamin Gaignard (TVO_SYNC_MAIN_VTG_SET_2 << TVO_SYNC_HD_DCS_SHIFT) 351cdfbff78SBenjamin Gaignard | TVO_SYNC_MAIN_VTG_SET_3, 352cdfbff78SBenjamin Gaignard TVO_HD_SYNC_SEL); 353cdfbff78SBenjamin Gaignard 354cdfbff78SBenjamin Gaignard /* power up HD DAC */ 355cdfbff78SBenjamin Gaignard tvout_write(tvout, 0, TVO_HD_DAC_CFG_OFF); 356cdfbff78SBenjamin Gaignard } 357cdfbff78SBenjamin Gaignard 358cdfbff78SBenjamin Gaignard static void sti_tvout_encoder_dpms(struct drm_encoder *encoder, int mode) 359cdfbff78SBenjamin Gaignard { 360cdfbff78SBenjamin Gaignard } 361cdfbff78SBenjamin Gaignard 362cdfbff78SBenjamin Gaignard static bool sti_tvout_encoder_mode_fixup(struct drm_encoder *encoder, 363cdfbff78SBenjamin Gaignard const struct drm_display_mode *mode, 364cdfbff78SBenjamin Gaignard struct drm_display_mode *adjusted_mode) 365cdfbff78SBenjamin Gaignard { 366cdfbff78SBenjamin Gaignard return true; 367cdfbff78SBenjamin Gaignard } 368cdfbff78SBenjamin Gaignard 369cdfbff78SBenjamin Gaignard static void sti_tvout_encoder_mode_set(struct drm_encoder *encoder, 370cdfbff78SBenjamin Gaignard struct drm_display_mode *mode, 371cdfbff78SBenjamin Gaignard struct drm_display_mode *adjusted_mode) 372cdfbff78SBenjamin Gaignard { 373cdfbff78SBenjamin Gaignard } 374cdfbff78SBenjamin Gaignard 375cdfbff78SBenjamin Gaignard static void sti_tvout_encoder_prepare(struct drm_encoder *encoder) 376cdfbff78SBenjamin Gaignard { 377cdfbff78SBenjamin Gaignard } 378cdfbff78SBenjamin Gaignard 379cdfbff78SBenjamin Gaignard static void sti_tvout_encoder_destroy(struct drm_encoder *encoder) 380cdfbff78SBenjamin Gaignard { 381cdfbff78SBenjamin Gaignard struct sti_tvout_encoder *sti_encoder = to_sti_tvout_encoder(encoder); 382cdfbff78SBenjamin Gaignard 383cdfbff78SBenjamin Gaignard drm_encoder_cleanup(encoder); 384cdfbff78SBenjamin Gaignard kfree(sti_encoder); 385cdfbff78SBenjamin Gaignard } 386cdfbff78SBenjamin Gaignard 387cdfbff78SBenjamin Gaignard static const struct drm_encoder_funcs sti_tvout_encoder_funcs = { 388cdfbff78SBenjamin Gaignard .destroy = sti_tvout_encoder_destroy, 389cdfbff78SBenjamin Gaignard }; 390cdfbff78SBenjamin Gaignard 391cdfbff78SBenjamin Gaignard static void sti_hda_encoder_commit(struct drm_encoder *encoder) 392cdfbff78SBenjamin Gaignard { 393cdfbff78SBenjamin Gaignard struct sti_tvout *tvout = to_sti_tvout(encoder); 394cdfbff78SBenjamin Gaignard 395cdfbff78SBenjamin Gaignard tvout_hda_start(tvout, true); 396cdfbff78SBenjamin Gaignard } 397cdfbff78SBenjamin Gaignard 398cdfbff78SBenjamin Gaignard static void sti_hda_encoder_disable(struct drm_encoder *encoder) 399cdfbff78SBenjamin Gaignard { 400cdfbff78SBenjamin Gaignard struct sti_tvout *tvout = to_sti_tvout(encoder); 401cdfbff78SBenjamin Gaignard 402cdfbff78SBenjamin Gaignard /* reset VIP register */ 403cdfbff78SBenjamin Gaignard tvout_write(tvout, 0x0, TVO_VIP_HDF); 404cdfbff78SBenjamin Gaignard 405cdfbff78SBenjamin Gaignard /* power down HD DAC */ 406cdfbff78SBenjamin Gaignard tvout_write(tvout, 1, TVO_HD_DAC_CFG_OFF); 407cdfbff78SBenjamin Gaignard } 408cdfbff78SBenjamin Gaignard 409cdfbff78SBenjamin Gaignard static const struct drm_encoder_helper_funcs sti_hda_encoder_helper_funcs = { 410cdfbff78SBenjamin Gaignard .dpms = sti_tvout_encoder_dpms, 411cdfbff78SBenjamin Gaignard .mode_fixup = sti_tvout_encoder_mode_fixup, 412cdfbff78SBenjamin Gaignard .mode_set = sti_tvout_encoder_mode_set, 413cdfbff78SBenjamin Gaignard .prepare = sti_tvout_encoder_prepare, 414cdfbff78SBenjamin Gaignard .commit = sti_hda_encoder_commit, 415cdfbff78SBenjamin Gaignard .disable = sti_hda_encoder_disable, 416cdfbff78SBenjamin Gaignard }; 417cdfbff78SBenjamin Gaignard 418cdfbff78SBenjamin Gaignard static struct drm_encoder *sti_tvout_create_hda_encoder(struct drm_device *dev, 419cdfbff78SBenjamin Gaignard struct sti_tvout *tvout) 420cdfbff78SBenjamin Gaignard { 421cdfbff78SBenjamin Gaignard struct sti_tvout_encoder *encoder; 422cdfbff78SBenjamin Gaignard struct drm_encoder *drm_encoder; 423cdfbff78SBenjamin Gaignard 424cdfbff78SBenjamin Gaignard encoder = devm_kzalloc(tvout->dev, sizeof(*encoder), GFP_KERNEL); 425cdfbff78SBenjamin Gaignard if (!encoder) 426cdfbff78SBenjamin Gaignard return NULL; 427cdfbff78SBenjamin Gaignard 428cdfbff78SBenjamin Gaignard encoder->tvout = tvout; 429cdfbff78SBenjamin Gaignard 430cdfbff78SBenjamin Gaignard drm_encoder = (struct drm_encoder *) encoder; 431cdfbff78SBenjamin Gaignard 432cdfbff78SBenjamin Gaignard drm_encoder->possible_crtcs = ENCODER_MAIN_CRTC_MASK; 433cdfbff78SBenjamin Gaignard drm_encoder->possible_clones = 1 << 0; 434cdfbff78SBenjamin Gaignard 435cdfbff78SBenjamin Gaignard drm_encoder_init(dev, drm_encoder, 436cdfbff78SBenjamin Gaignard &sti_tvout_encoder_funcs, DRM_MODE_ENCODER_DAC); 437cdfbff78SBenjamin Gaignard 438cdfbff78SBenjamin Gaignard drm_encoder_helper_add(drm_encoder, &sti_hda_encoder_helper_funcs); 439cdfbff78SBenjamin Gaignard 440cdfbff78SBenjamin Gaignard return drm_encoder; 441cdfbff78SBenjamin Gaignard } 442cdfbff78SBenjamin Gaignard 443cdfbff78SBenjamin Gaignard static void sti_hdmi_encoder_commit(struct drm_encoder *encoder) 444cdfbff78SBenjamin Gaignard { 445cdfbff78SBenjamin Gaignard struct sti_tvout *tvout = to_sti_tvout(encoder); 446cdfbff78SBenjamin Gaignard 447cdfbff78SBenjamin Gaignard tvout_hdmi_start(tvout, true); 448cdfbff78SBenjamin Gaignard } 449cdfbff78SBenjamin Gaignard 450cdfbff78SBenjamin Gaignard static void sti_hdmi_encoder_disable(struct drm_encoder *encoder) 451cdfbff78SBenjamin Gaignard { 452cdfbff78SBenjamin Gaignard struct sti_tvout *tvout = to_sti_tvout(encoder); 453cdfbff78SBenjamin Gaignard 454cdfbff78SBenjamin Gaignard /* reset VIP register */ 455cdfbff78SBenjamin Gaignard tvout_write(tvout, 0x0, TVO_VIP_HDMI); 456cdfbff78SBenjamin Gaignard } 457cdfbff78SBenjamin Gaignard 458cdfbff78SBenjamin Gaignard static const struct drm_encoder_helper_funcs sti_hdmi_encoder_helper_funcs = { 459cdfbff78SBenjamin Gaignard .dpms = sti_tvout_encoder_dpms, 460cdfbff78SBenjamin Gaignard .mode_fixup = sti_tvout_encoder_mode_fixup, 461cdfbff78SBenjamin Gaignard .mode_set = sti_tvout_encoder_mode_set, 462cdfbff78SBenjamin Gaignard .prepare = sti_tvout_encoder_prepare, 463cdfbff78SBenjamin Gaignard .commit = sti_hdmi_encoder_commit, 464cdfbff78SBenjamin Gaignard .disable = sti_hdmi_encoder_disable, 465cdfbff78SBenjamin Gaignard }; 466cdfbff78SBenjamin Gaignard 467cdfbff78SBenjamin Gaignard static struct drm_encoder *sti_tvout_create_hdmi_encoder(struct drm_device *dev, 468cdfbff78SBenjamin Gaignard struct sti_tvout *tvout) 469cdfbff78SBenjamin Gaignard { 470cdfbff78SBenjamin Gaignard struct sti_tvout_encoder *encoder; 471cdfbff78SBenjamin Gaignard struct drm_encoder *drm_encoder; 472cdfbff78SBenjamin Gaignard 473cdfbff78SBenjamin Gaignard encoder = devm_kzalloc(tvout->dev, sizeof(*encoder), GFP_KERNEL); 474cdfbff78SBenjamin Gaignard if (!encoder) 475cdfbff78SBenjamin Gaignard return NULL; 476cdfbff78SBenjamin Gaignard 477cdfbff78SBenjamin Gaignard encoder->tvout = tvout; 478cdfbff78SBenjamin Gaignard 479cdfbff78SBenjamin Gaignard drm_encoder = (struct drm_encoder *) encoder; 480cdfbff78SBenjamin Gaignard 481cdfbff78SBenjamin Gaignard drm_encoder->possible_crtcs = ENCODER_MAIN_CRTC_MASK; 482cdfbff78SBenjamin Gaignard drm_encoder->possible_clones = 1 << 1; 483cdfbff78SBenjamin Gaignard 484cdfbff78SBenjamin Gaignard drm_encoder_init(dev, drm_encoder, 485cdfbff78SBenjamin Gaignard &sti_tvout_encoder_funcs, DRM_MODE_ENCODER_TMDS); 486cdfbff78SBenjamin Gaignard 487cdfbff78SBenjamin Gaignard drm_encoder_helper_add(drm_encoder, &sti_hdmi_encoder_helper_funcs); 488cdfbff78SBenjamin Gaignard 489cdfbff78SBenjamin Gaignard return drm_encoder; 490cdfbff78SBenjamin Gaignard } 491cdfbff78SBenjamin Gaignard 492cdfbff78SBenjamin Gaignard static void sti_tvout_create_encoders(struct drm_device *dev, 493cdfbff78SBenjamin Gaignard struct sti_tvout *tvout) 494cdfbff78SBenjamin Gaignard { 495cdfbff78SBenjamin Gaignard tvout->hdmi = sti_tvout_create_hdmi_encoder(dev, tvout); 496cdfbff78SBenjamin Gaignard tvout->hda = sti_tvout_create_hda_encoder(dev, tvout); 497cdfbff78SBenjamin Gaignard } 498cdfbff78SBenjamin Gaignard 499cdfbff78SBenjamin Gaignard static void sti_tvout_destroy_encoders(struct sti_tvout *tvout) 500cdfbff78SBenjamin Gaignard { 501cdfbff78SBenjamin Gaignard if (tvout->hdmi) 502cdfbff78SBenjamin Gaignard drm_encoder_cleanup(tvout->hdmi); 503cdfbff78SBenjamin Gaignard tvout->hdmi = NULL; 504cdfbff78SBenjamin Gaignard 505cdfbff78SBenjamin Gaignard if (tvout->hda) 506cdfbff78SBenjamin Gaignard drm_encoder_cleanup(tvout->hda); 507cdfbff78SBenjamin Gaignard tvout->hda = NULL; 508cdfbff78SBenjamin Gaignard } 509cdfbff78SBenjamin Gaignard 510cdfbff78SBenjamin Gaignard static int sti_tvout_bind(struct device *dev, struct device *master, void *data) 511cdfbff78SBenjamin Gaignard { 512cdfbff78SBenjamin Gaignard struct sti_tvout *tvout = dev_get_drvdata(dev); 513cdfbff78SBenjamin Gaignard struct drm_device *drm_dev = data; 514cdfbff78SBenjamin Gaignard unsigned int i; 515cdfbff78SBenjamin Gaignard int ret; 516cdfbff78SBenjamin Gaignard 517cdfbff78SBenjamin Gaignard tvout->drm_dev = drm_dev; 518cdfbff78SBenjamin Gaignard 519cdfbff78SBenjamin Gaignard /* set preformatter matrix */ 520cdfbff78SBenjamin Gaignard for (i = 0; i < 8; i++) { 521cdfbff78SBenjamin Gaignard tvout_write(tvout, rgb_to_ycbcr_601[i], 522cdfbff78SBenjamin Gaignard TVO_CSC_MAIN_M0 + (i * 4)); 523cdfbff78SBenjamin Gaignard tvout_write(tvout, rgb_to_ycbcr_601[i], 524cdfbff78SBenjamin Gaignard TVO_CSC_AUX_M0 + (i * 4)); 525cdfbff78SBenjamin Gaignard } 526cdfbff78SBenjamin Gaignard 527cdfbff78SBenjamin Gaignard sti_tvout_create_encoders(drm_dev, tvout); 528cdfbff78SBenjamin Gaignard 529cdfbff78SBenjamin Gaignard ret = component_bind_all(dev, drm_dev); 530cdfbff78SBenjamin Gaignard if (ret) 531cdfbff78SBenjamin Gaignard sti_tvout_destroy_encoders(tvout); 532cdfbff78SBenjamin Gaignard 533cdfbff78SBenjamin Gaignard return ret; 534cdfbff78SBenjamin Gaignard } 535cdfbff78SBenjamin Gaignard 536cdfbff78SBenjamin Gaignard static void sti_tvout_unbind(struct device *dev, struct device *master, 537cdfbff78SBenjamin Gaignard void *data) 538cdfbff78SBenjamin Gaignard { 539cdfbff78SBenjamin Gaignard /* do nothing */ 540cdfbff78SBenjamin Gaignard } 541cdfbff78SBenjamin Gaignard 542cdfbff78SBenjamin Gaignard static const struct component_ops sti_tvout_ops = { 543cdfbff78SBenjamin Gaignard .bind = sti_tvout_bind, 544cdfbff78SBenjamin Gaignard .unbind = sti_tvout_unbind, 545cdfbff78SBenjamin Gaignard }; 546cdfbff78SBenjamin Gaignard 547cdfbff78SBenjamin Gaignard static int compare_of(struct device *dev, void *data) 548cdfbff78SBenjamin Gaignard { 549cdfbff78SBenjamin Gaignard return dev->of_node == data; 550cdfbff78SBenjamin Gaignard } 551cdfbff78SBenjamin Gaignard 552cdfbff78SBenjamin Gaignard static int sti_tvout_master_bind(struct device *dev) 553cdfbff78SBenjamin Gaignard { 554cdfbff78SBenjamin Gaignard return 0; 555cdfbff78SBenjamin Gaignard } 556cdfbff78SBenjamin Gaignard 557cdfbff78SBenjamin Gaignard static void sti_tvout_master_unbind(struct device *dev) 558cdfbff78SBenjamin Gaignard { 559cdfbff78SBenjamin Gaignard /* do nothing */ 560cdfbff78SBenjamin Gaignard } 561cdfbff78SBenjamin Gaignard 562cdfbff78SBenjamin Gaignard static const struct component_master_ops sti_tvout_master_ops = { 563cdfbff78SBenjamin Gaignard .bind = sti_tvout_master_bind, 564cdfbff78SBenjamin Gaignard .unbind = sti_tvout_master_unbind, 565cdfbff78SBenjamin Gaignard }; 566cdfbff78SBenjamin Gaignard 567cdfbff78SBenjamin Gaignard static int sti_tvout_probe(struct platform_device *pdev) 568cdfbff78SBenjamin Gaignard { 569cdfbff78SBenjamin Gaignard struct device *dev = &pdev->dev; 570cdfbff78SBenjamin Gaignard struct device_node *node = dev->of_node; 571cdfbff78SBenjamin Gaignard struct sti_tvout *tvout; 572cdfbff78SBenjamin Gaignard struct resource *res; 573cdfbff78SBenjamin Gaignard struct device_node *child_np; 574cdfbff78SBenjamin Gaignard struct component_match *match = NULL; 575cdfbff78SBenjamin Gaignard 576cdfbff78SBenjamin Gaignard DRM_INFO("%s\n", __func__); 577cdfbff78SBenjamin Gaignard 578cdfbff78SBenjamin Gaignard if (!node) 579cdfbff78SBenjamin Gaignard return -ENODEV; 580cdfbff78SBenjamin Gaignard 581cdfbff78SBenjamin Gaignard tvout = devm_kzalloc(dev, sizeof(*tvout), GFP_KERNEL); 582cdfbff78SBenjamin Gaignard if (!tvout) 583cdfbff78SBenjamin Gaignard return -ENOMEM; 584cdfbff78SBenjamin Gaignard 585cdfbff78SBenjamin Gaignard tvout->dev = dev; 586cdfbff78SBenjamin Gaignard 587cdfbff78SBenjamin Gaignard /* get Memory ressources */ 588cdfbff78SBenjamin Gaignard res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tvout-reg"); 589cdfbff78SBenjamin Gaignard if (!res) { 590cdfbff78SBenjamin Gaignard DRM_ERROR("Invalid glue resource\n"); 591cdfbff78SBenjamin Gaignard return -ENOMEM; 592cdfbff78SBenjamin Gaignard } 593cdfbff78SBenjamin Gaignard tvout->regs = devm_ioremap_nocache(dev, res->start, resource_size(res)); 594*31f32a21SWei Yongjun if (!tvout->regs) 595*31f32a21SWei Yongjun return -ENOMEM; 596cdfbff78SBenjamin Gaignard 597cdfbff78SBenjamin Gaignard /* get reset resources */ 598cdfbff78SBenjamin Gaignard tvout->reset = devm_reset_control_get(dev, "tvout"); 599cdfbff78SBenjamin Gaignard /* take tvout out of reset */ 600cdfbff78SBenjamin Gaignard if (!IS_ERR(tvout->reset)) 601cdfbff78SBenjamin Gaignard reset_control_deassert(tvout->reset); 602cdfbff78SBenjamin Gaignard 603cdfbff78SBenjamin Gaignard platform_set_drvdata(pdev, tvout); 604cdfbff78SBenjamin Gaignard 605cdfbff78SBenjamin Gaignard of_platform_populate(node, NULL, NULL, dev); 606cdfbff78SBenjamin Gaignard 607cdfbff78SBenjamin Gaignard child_np = of_get_next_available_child(node, NULL); 608cdfbff78SBenjamin Gaignard 609cdfbff78SBenjamin Gaignard while (child_np) { 610cdfbff78SBenjamin Gaignard component_match_add(dev, &match, compare_of, child_np); 611cdfbff78SBenjamin Gaignard of_node_put(child_np); 612cdfbff78SBenjamin Gaignard child_np = of_get_next_available_child(node, child_np); 613cdfbff78SBenjamin Gaignard } 614cdfbff78SBenjamin Gaignard 615cdfbff78SBenjamin Gaignard component_master_add_with_match(dev, &sti_tvout_master_ops, match); 616cdfbff78SBenjamin Gaignard 617cdfbff78SBenjamin Gaignard return component_add(dev, &sti_tvout_ops); 618cdfbff78SBenjamin Gaignard } 619cdfbff78SBenjamin Gaignard 620cdfbff78SBenjamin Gaignard static int sti_tvout_remove(struct platform_device *pdev) 621cdfbff78SBenjamin Gaignard { 622cdfbff78SBenjamin Gaignard component_master_del(&pdev->dev, &sti_tvout_master_ops); 623cdfbff78SBenjamin Gaignard component_del(&pdev->dev, &sti_tvout_ops); 624cdfbff78SBenjamin Gaignard return 0; 625cdfbff78SBenjamin Gaignard } 626cdfbff78SBenjamin Gaignard 627cdfbff78SBenjamin Gaignard static struct of_device_id tvout_of_match[] = { 628cdfbff78SBenjamin Gaignard { .compatible = "st,stih416-tvout", }, 629cdfbff78SBenjamin Gaignard { .compatible = "st,stih407-tvout", }, 630cdfbff78SBenjamin Gaignard { /* end node */ } 631cdfbff78SBenjamin Gaignard }; 632cdfbff78SBenjamin Gaignard MODULE_DEVICE_TABLE(of, tvout_of_match); 633cdfbff78SBenjamin Gaignard 634cdfbff78SBenjamin Gaignard struct platform_driver sti_tvout_driver = { 635cdfbff78SBenjamin Gaignard .driver = { 636cdfbff78SBenjamin Gaignard .name = "sti-tvout", 637cdfbff78SBenjamin Gaignard .owner = THIS_MODULE, 638cdfbff78SBenjamin Gaignard .of_match_table = tvout_of_match, 639cdfbff78SBenjamin Gaignard }, 640cdfbff78SBenjamin Gaignard .probe = sti_tvout_probe, 641cdfbff78SBenjamin Gaignard .remove = sti_tvout_remove, 642cdfbff78SBenjamin Gaignard }; 643cdfbff78SBenjamin Gaignard 644cdfbff78SBenjamin Gaignard module_platform_driver(sti_tvout_driver); 645cdfbff78SBenjamin Gaignard 646cdfbff78SBenjamin Gaignard MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>"); 647cdfbff78SBenjamin Gaignard MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver"); 648cdfbff78SBenjamin Gaignard MODULE_LICENSE("GPL"); 649