cregit-Linux how code gets into the kernel

Release 4.7 drivers/gpu/drm/sti/sti_hdmi.c

/*
 * Copyright (C) STMicroelectronics SA 2014
 * Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
 * License terms:  GNU General Public License (GPL), version 2
 */

#include <linux/clk.h>
#include <linux/component.h>
#include <linux/debugfs.h>
#include <linux/hdmi.h>
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/reset.h>

#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>

#include "sti_hdmi.h"
#include "sti_hdmi_tx3g4c28phy.h"
#include "sti_hdmi_tx3g0c55phy.h"
#include "sti_vtg.h"


#define HDMI_CFG                        0x0000

#define HDMI_INT_EN                     0x0004

#define HDMI_INT_STA                    0x0008

#define HDMI_INT_CLR                    0x000C

#define HDMI_STA                        0x0010

#define HDMI_ACTIVE_VID_XMIN            0x0100

#define HDMI_ACTIVE_VID_XMAX            0x0104

#define HDMI_ACTIVE_VID_YMIN            0x0108

#define HDMI_ACTIVE_VID_YMAX            0x010C

#define HDMI_DFLT_CHL0_DAT              0x0110

#define HDMI_DFLT_CHL1_DAT              0x0114

#define HDMI_DFLT_CHL2_DAT              0x0118

#define HDMI_SW_DI_1_HEAD_WORD          0x0210

#define HDMI_SW_DI_1_PKT_WORD0          0x0214

#define HDMI_SW_DI_1_PKT_WORD1          0x0218

#define HDMI_SW_DI_1_PKT_WORD2          0x021C

#define HDMI_SW_DI_1_PKT_WORD3          0x0220

#define HDMI_SW_DI_1_PKT_WORD4          0x0224

#define HDMI_SW_DI_1_PKT_WORD5          0x0228

#define HDMI_SW_DI_1_PKT_WORD6          0x022C

#define HDMI_SW_DI_CFG                  0x0230

#define HDMI_SW_DI_2_HEAD_WORD          0x0600

#define HDMI_SW_DI_2_PKT_WORD0          0x0604

#define HDMI_SW_DI_2_PKT_WORD1          0x0608

#define HDMI_SW_DI_2_PKT_WORD2          0x060C

#define HDMI_SW_DI_2_PKT_WORD3          0x0610

#define HDMI_SW_DI_2_PKT_WORD4          0x0614

#define HDMI_SW_DI_2_PKT_WORD5          0x0618

#define HDMI_SW_DI_2_PKT_WORD6          0x061C

#define HDMI_SW_DI_3_HEAD_WORD          0x0620

#define HDMI_SW_DI_3_PKT_WORD0          0x0624

#define HDMI_SW_DI_3_PKT_WORD1          0x0628

#define HDMI_SW_DI_3_PKT_WORD2          0x062C

#define HDMI_SW_DI_3_PKT_WORD3          0x0630

#define HDMI_SW_DI_3_PKT_WORD4          0x0634

#define HDMI_SW_DI_3_PKT_WORD5          0x0638

#define HDMI_SW_DI_3_PKT_WORD6          0x063C


#define HDMI_IFRAME_SLOT_AVI            1

#define HDMI_IFRAME_SLOT_AUDIO          2

#define HDMI_IFRAME_SLOT_VENDOR         3


#define  XCAT(prefix, x, suffix)        prefix ## x ## suffix

#define  HDMI_SW_DI_N_HEAD_WORD(x)      XCAT(HDMI_SW_DI_, x, _HEAD_WORD)

#define  HDMI_SW_DI_N_PKT_WORD0(x)      XCAT(HDMI_SW_DI_, x, _PKT_WORD0)

#define  HDMI_SW_DI_N_PKT_WORD1(x)      XCAT(HDMI_SW_DI_, x, _PKT_WORD1)

#define  HDMI_SW_DI_N_PKT_WORD2(x)      XCAT(HDMI_SW_DI_, x, _PKT_WORD2)

#define  HDMI_SW_DI_N_PKT_WORD3(x)      XCAT(HDMI_SW_DI_, x, _PKT_WORD3)

#define  HDMI_SW_DI_N_PKT_WORD4(x)      XCAT(HDMI_SW_DI_, x, _PKT_WORD4)

#define  HDMI_SW_DI_N_PKT_WORD5(x)      XCAT(HDMI_SW_DI_, x, _PKT_WORD5)

#define  HDMI_SW_DI_N_PKT_WORD6(x)      XCAT(HDMI_SW_DI_, x, _PKT_WORD6)


#define HDMI_SW_DI_MAX_WORD             7


#define HDMI_IFRAME_DISABLED            0x0

#define HDMI_IFRAME_SINGLE_SHOT         0x1

#define HDMI_IFRAME_FIELD               0x2

#define HDMI_IFRAME_FRAME               0x3

#define HDMI_IFRAME_MASK                0x3

#define HDMI_IFRAME_CFG_DI_N(x, n)       ((x) << ((n-1)*4)) 
/* n from 1 to 6 */


#define HDMI_CFG_DEVICE_EN              BIT(0)

#define HDMI_CFG_HDMI_NOT_DVI           BIT(1)

#define HDMI_CFG_HDCP_EN                BIT(2)

#define HDMI_CFG_ESS_NOT_OESS           BIT(3)

#define HDMI_CFG_H_SYNC_POL_NEG         BIT(4)

#define HDMI_CFG_SINK_TERM_DET_EN       BIT(5)

#define HDMI_CFG_V_SYNC_POL_NEG         BIT(6)

#define HDMI_CFG_422_EN                 BIT(8)

#define HDMI_CFG_FIFO_OVERRUN_CLR       BIT(12)

#define HDMI_CFG_FIFO_UNDERRUN_CLR      BIT(13)

#define HDMI_CFG_SW_RST_EN              BIT(31)


#define HDMI_INT_GLOBAL                 BIT(0)

#define HDMI_INT_SW_RST                 BIT(1)

#define HDMI_INT_PIX_CAP                BIT(3)

#define HDMI_INT_HOT_PLUG               BIT(4)

#define HDMI_INT_DLL_LCK                BIT(5)

#define HDMI_INT_NEW_FRAME              BIT(6)

#define HDMI_INT_GENCTRL_PKT            BIT(7)

#define HDMI_INT_SINK_TERM_PRESENT      BIT(11)


#define HDMI_DEFAULT_INT (HDMI_INT_SINK_TERM_PRESENT \
                        | HDMI_INT_DLL_LCK \
                        | HDMI_INT_HOT_PLUG \
                        | HDMI_INT_GLOBAL)


#define HDMI_WORKING_INT (HDMI_INT_SINK_TERM_PRESENT \
                        | HDMI_INT_GENCTRL_PKT \
                        | HDMI_INT_NEW_FRAME \
                        | HDMI_INT_DLL_LCK \
                        | HDMI_INT_HOT_PLUG \
                        | HDMI_INT_PIX_CAP \
                        | HDMI_INT_SW_RST \
                        | HDMI_INT_GLOBAL)


#define HDMI_STA_SW_RST                 BIT(1)


#define HDMI_INFOFRAME_HEADER_TYPE(x)    (((x) & 0xff) <<  0)

#define HDMI_INFOFRAME_HEADER_VERSION(x) (((x) & 0xff) <<  8)

#define HDMI_INFOFRAME_HEADER_LEN(x)     (((x) & 0x0f) << 16)


struct sti_hdmi_connector {
	
struct drm_connector drm_connector;
	
struct drm_encoder *encoder;
	
struct sti_hdmi *hdmi;
	
struct drm_property *colorspace_property;
	
struct drm_property *hdmi_mode_property;
};


#define to_sti_hdmi_connector(x) \
	container_of(x, struct sti_hdmi_connector, drm_connector)


u32 hdmi_read(struct sti_hdmi *hdmi, int offset) { return readl(hdmi->regs + offset); }

Contributors

PersonTokensPropCommitsCommitProp
benjamin gaignardbenjamin gaignard23100.00%1100.00%
Total23100.00%1100.00%


void hdmi_write(struct sti_hdmi *hdmi, u32 val, int offset) { writel(val, hdmi->regs + offset); }

Contributors

PersonTokensPropCommitsCommitProp
benjamin gaignardbenjamin gaignard27100.00%1100.00%
Total27100.00%1100.00%

/** * HDMI interrupt handler threaded * * @irq: irq number * @arg: connector structure */
static irqreturn_t hdmi_irq_thread(int irq, void *arg) { struct sti_hdmi *hdmi = arg; /* Hot plug/unplug IRQ */ if (hdmi->irq_status & HDMI_INT_HOT_PLUG) { hdmi->hpd = readl(hdmi->regs + HDMI_STA) & HDMI_STA_HOT_PLUG; if (hdmi->drm_dev) drm_helper_hpd_irq_event(hdmi->drm_dev); } /* Sw reset and PLL lock are exclusive so we can use the same * event to signal them */ if (hdmi->irq_status & (HDMI_INT_SW_RST | HDMI_INT_DLL_LCK)) { hdmi->event_received = true; wake_up_interruptible(&hdmi->wait_event); } return IRQ_HANDLED; }

Contributors

PersonTokensPropCommitsCommitProp
benjamin gaignardbenjamin gaignard91100.00%2100.00%
Total91100.00%2100.00%

/** * HDMI interrupt handler * * @irq: irq number * @arg: connector structure */
static irqreturn_t hdmi_irq(int irq, void *arg) { struct sti_hdmi *hdmi = arg; /* read interrupt status */ hdmi->irq_status = hdmi_read(hdmi, HDMI_INT_STA); /* clear interrupt status */ hdmi_write(hdmi, hdmi->irq_status, HDMI_INT_CLR); /* force sync bus write */ hdmi_read(hdmi, HDMI_INT_STA); return IRQ_WAKE_THREAD; }

Contributors

PersonTokensPropCommitsCommitProp
benjamin gaignardbenjamin gaignard55100.00%1100.00%
Total55100.00%1100.00%

/** * Set hdmi active area depending on the drm display mode selected * * @hdmi: pointer on the hdmi internal structure */
static void hdmi_active_area(struct sti_hdmi *hdmi) { u32 xmin, xmax; u32 ymin, ymax; xmin = sti_vtg_get_pixel_number(hdmi->mode, 1); xmax = sti_vtg_get_pixel_number(hdmi->mode, hdmi->mode.hdisplay); ymin = sti_vtg_get_line_number(hdmi->mode, 0); ymax = sti_vtg_get_line_number(hdmi->mode, hdmi->mode.vdisplay - 1); hdmi_write(hdmi, xmin, HDMI_ACTIVE_VID_XMIN); hdmi_write(hdmi, xmax, HDMI_ACTIVE_VID_XMAX); hdmi_write(hdmi, ymin, HDMI_ACTIVE_VID_YMIN); hdmi_write(hdmi, ymax, HDMI_ACTIVE_VID_YMAX); }

Contributors

PersonTokensPropCommitsCommitProp
benjamin gaignardbenjamin gaignard11099.10%150.00%
vincent abriouvincent abriou10.90%150.00%
Total111100.00%2100.00%

/** * Overall hdmi configuration * * @hdmi: pointer on the hdmi internal structure */
static void hdmi_config(struct sti_hdmi *hdmi) { u32 conf; DRM_DEBUG_DRIVER("\n"); /* Clear overrun and underrun fifo */ conf = HDMI_CFG_FIFO_OVERRUN_CLR | HDMI_CFG_FIFO_UNDERRUN_CLR; /* Select encryption type and the framing mode */ conf |= HDMI_CFG_ESS_NOT_OESS; if (hdmi->hdmi_mode == HDMI_MODE_HDMI) conf |= HDMI_CFG_HDMI_NOT_DVI; /* Enable sink term detection */ conf |= HDMI_CFG_SINK_TERM_DET_EN; /* Set Hsync polarity */ if (hdmi->mode.flags & DRM_MODE_FLAG_NHSYNC) { DRM_DEBUG_DRIVER("H Sync Negative\n"); conf |= HDMI_CFG_H_SYNC_POL_NEG; } /* Set Vsync polarity */ if (hdmi->mode.flags & DRM_MODE_FLAG_NVSYNC) { DRM_DEBUG_DRIVER("V Sync Negative\n"); conf |= HDMI_CFG_V_SYNC_POL_NEG; } /* Enable HDMI */ conf |= HDMI_CFG_DEVICE_EN; hdmi_write(hdmi, conf, HDMI_CFG); }

Contributors

PersonTokensPropCommitsCommitProp
benjamin gaignardbenjamin gaignard9387.74%150.00%
vincent abriouvincent abriou1312.26%150.00%
Total106100.00%2100.00%

/* * Helper to reset info frame * * @hdmi: pointer on the hdmi internal structure * @slot: infoframe to reset */
static void hdmi_infoframe_reset(struct sti_hdmi *hdmi, u32 slot) { u32 val, i; u32 head_offset, pack_offset; switch (slot) { case HDMI_IFRAME_SLOT_AVI: head_offset = HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_AVI); pack_offset = HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_AVI); break; case HDMI_IFRAME_SLOT_AUDIO: head_offset = HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_AUDIO); pack_offset = HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_AUDIO); break; case HDMI_IFRAME_SLOT_VENDOR: head_offset = HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_VENDOR); pack_offset = HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_VENDOR); break; default: DRM_ERROR("unsupported infoframe slot: %#x\n", slot); return; } /* Disable transmission for the selected slot */ val = hdmi_read(hdmi, HDMI_SW_DI_CFG); val &= ~HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, slot); hdmi_write(hdmi, val, HDMI_SW_DI_CFG); /* Reset info frame registers */ hdmi_write(hdmi, 0x0, head_offset); for (i = 0; i < HDMI_SW_DI_MAX_WORD; i += sizeof(u32)) hdmi_write(hdmi, 0x0, pack_offset + i); }

Contributors

PersonTokensPropCommitsCommitProp
vincent abriouvincent abriou160100.00%2100.00%
Total160100.00%2100.00%

/** * Helper to concatenate infoframe in 32 bits word * * @ptr: pointer on the hdmi internal structure * @data: infoframe to write * @size: size to write */
static inline unsigned int hdmi_infoframe_subpack(const u8 *ptr, size_t size) { unsigned long value = 0; size_t i; for (i = size; i > 0; i--) value = (value << 8) | ptr[i - 1]; return value; }

Contributors

PersonTokensPropCommitsCommitProp
arnaud pouliquenarnaud pouliquen4580.36%150.00%
benjamin gaignardbenjamin gaignard1119.64%150.00%
Total56100.00%2100.00%

/** * Helper to write info frame * * @hdmi: pointer on the hdmi internal structure * @data: infoframe to write * @size: size to write */
static void hdmi_infoframe_write_infopack(struct sti_hdmi *hdmi, const u8 *data, size_t size) { const u8 *ptr = data; u32 val, slot, mode, i; u32 head_offset, pack_offset; switch (*ptr) { case HDMI_INFOFRAME_TYPE_AVI: slot = HDMI_IFRAME_SLOT_AVI; mode = HDMI_IFRAME_FIELD; head_offset = HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_AVI); pack_offset = HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_AVI); break; case HDMI_INFOFRAME_TYPE_AUDIO: slot = HDMI_IFRAME_SLOT_AUDIO; mode = HDMI_IFRAME_FRAME; head_offset = HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_AUDIO); pack_offset = HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_AUDIO); break; case HDMI_INFOFRAME_TYPE_VENDOR: slot = HDMI_IFRAME_SLOT_VENDOR; mode = HDMI_IFRAME_FRAME; head_offset = HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_VENDOR); pack_offset = HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_VENDOR); break; default: DRM_ERROR("unsupported infoframe type: %#x\n", *ptr); return; } /* Disable transmission slot for updated infoframe */ val = hdmi_read(hdmi, HDMI_SW_DI_CFG); val &= ~HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, slot); hdmi_write(hdmi, val, HDMI_SW_DI_CFG); val = HDMI_INFOFRAME_HEADER_TYPE(*ptr++); val |= HDMI_INFOFRAME_HEADER_VERSION(*ptr++); val |= HDMI_INFOFRAME_HEADER_LEN(*ptr++); writel(val, hdmi->regs + head_offset); /* * Each subpack contains 4 bytes * The First Bytes of the first subpacket must contain the checksum * Packet size is increase by one. */ size = size - HDMI_INFOFRAME_HEADER_SIZE + 1; for (i = 0; i < size; i += sizeof(u32)) { size_t num; num = min_t(size_t, size - i, sizeof(u32)); val = hdmi_infoframe_subpack(ptr, num); ptr += sizeof(u32); writel(val, hdmi->regs + pack_offset + i); } /* Enable transmission slot for updated infoframe */ val = hdmi_read(hdmi, HDMI_SW_DI_CFG); val |= HDMI_IFRAME_CFG_DI_N(mode, slot); hdmi_write(hdmi, val, HDMI_SW_DI_CFG); }

Contributors

PersonTokensPropCommitsCommitProp
arnaud pouliquenarnaud pouliquen17356.54%125.00%
benjamin gaignardbenjamin gaignard9631.37%125.00%
vincent abriouvincent abriou3712.09%250.00%
Total306100.00%4100.00%

/** * Prepare and configure the AVI infoframe * * AVI infoframe are transmitted at least once per two video field and * contains information about HDMI transmission mode such as color space, * colorimetry, ... * * @hdmi: pointer on the hdmi internal structure * * Return negative value if error occurs */
static int hdmi_avi_infoframe_config(struct sti_hdmi *hdmi) { struct drm_display_mode *mode = &hdmi->mode; struct hdmi_avi_infoframe infoframe; u8 buffer[HDMI_INFOFRAME_SIZE(AVI)]; int ret; DRM_DEBUG_DRIVER("\n"); ret = drm_hdmi_avi_infoframe_from_display_mode(&infoframe, mode); if (ret < 0) { DRM_ERROR("failed to setup AVI infoframe: %d\n", ret); return ret; } /* fixed infoframe configuration not linked to the mode */ infoframe.colorspace = hdmi->colorspace; infoframe.quantization_range = HDMI_QUANTIZATION_RANGE_DEFAULT; infoframe.colorimetry = HDMI_COLORIMETRY_NONE; ret = hdmi_avi_infoframe_pack(&infoframe, buffer, sizeof(buffer)); if (ret < 0) { DRM_ERROR("failed to pack AVI infoframe: %d\n", ret); return ret; } hdmi_infoframe_write_infopack(hdmi, buffer, ret); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
arnaud pouliquenarnaud pouliquen11181.62%125.00%
benjamin gaignardbenjamin gaignard2014.71%125.00%
vincent abriouvincent abriou53.68%250.00%
Total136100.00%4100.00%

/** * Prepare and configure the AUDIO infoframe * * AUDIO infoframe are transmitted once per frame and * contains information about HDMI transmission mode such as audio codec, * sample size, ... * * @hdmi: pointer on the hdmi internal structure * * Return negative value if error occurs */
static int hdmi_audio_infoframe_config(struct sti_hdmi *hdmi) { struct hdmi_audio_infoframe infofame; u8 buffer[HDMI_INFOFRAME_SIZE(AUDIO)]; int ret; ret = hdmi_audio_infoframe_init(&infofame); if (ret < 0) { DRM_ERROR("failed to setup audio infoframe: %d\n", ret); return ret; } infofame.channels = 2; ret = hdmi_audio_infoframe_pack(&infofame, buffer, sizeof(buffer)); if (ret < 0) { DRM_ERROR("failed to pack audio infoframe: %d\n", ret); return ret; } hdmi_infoframe_write_infopack(hdmi, buffer, ret); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
arnaud pouliquenarnaud pouliquen8076.92%133.33%
benjamin gaignardbenjamin gaignard1615.38%133.33%
vincent abriouvincent abriou87.69%133.33%
Total104100.00%3100.00%

/* * Prepare and configure the VS infoframe * * Vendor Specific infoframe are transmitted once per frame and * contains vendor specific information. * * @hdmi: pointer on the hdmi internal structure * * Return negative value if error occurs */ #define HDMI_VENDOR_INFOFRAME_MAX_SIZE 6
static int hdmi_vendor_infoframe_config(struct sti_hdmi *hdmi) { struct drm_display_mode *mode = &hdmi->mode; struct hdmi_vendor_infoframe infoframe; u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_VENDOR_INFOFRAME_MAX_SIZE]; int ret; DRM_DEBUG_DRIVER("\n"); ret = drm_hdmi_vendor_infoframe_from_display_mode(&infoframe, mode); if (ret < 0) { /* * Going into that statement does not means vendor infoframe * fails. It just informed us that vendor infoframe is not * needed for the selected mode. Only 4k or stereoscopic 3D * mode requires vendor infoframe. So just simply return 0. */ return 0; } ret = hdmi_vendor_infoframe_pack(&infoframe, buffer, sizeof(buffer)); if (ret < 0) { DRM_ERROR("failed to pack VS infoframe: %d\n", ret); return ret; } hdmi_infoframe_write_infopack(hdmi, buffer, ret); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
vincent abriouvincent abriou10294.44%150.00%
benjamin gaignardbenjamin gaignard65.56%150.00%
Total108100.00%2100.00%

/** * Software reset of the hdmi subsystem * * @hdmi: pointer on the hdmi internal structure * */ #define HDMI_TIMEOUT_SWRESET 100 /*milliseconds */
static void hdmi_swreset(struct sti_hdmi *hdmi) { u32 val; DRM_DEBUG_DRIVER("\n"); /* Enable hdmi_audio clock only during hdmi reset */ if (clk_prepare_enable(hdmi->clk_audio)) DRM_INFO("Failed to prepare/enable hdmi_audio clk\n"); /* Sw reset */ hdmi->event_received = false; val = hdmi_read(hdmi, HDMI_CFG); val |= HDMI_CFG_SW_RST_EN; hdmi_write(hdmi, val, HDMI_CFG); /* Wait reset completed */ wait_event_interruptible_timeout(hdmi->wait_event, hdmi->event_received == true, msecs_to_jiffies (HDMI_TIMEOUT_SWRESET)); /* * HDMI_STA_SW_RST bit is set to '1' when SW_RST bit in HDMI_CFG is * set to '1' and clk_audio is running. */ if ((hdmi_read(hdmi, HDMI_STA) & HDMI_STA_SW_RST) == 0) DRM_DEBUG_DRIVER("Warning: HDMI sw reset timeout occurs\n"); val = hdmi_read(hdmi, HDMI_CFG); val &= ~HDMI_CFG_SW_RST_EN; hdmi_write(hdmi, val, HDMI_CFG); /* Disable hdmi_audio clock. Not used anymore for drm purpose */ clk_disable_unprepare(hdmi->clk_audio); }

Contributors

PersonTokensPropCommitsCommitProp
benjamin gaignardbenjamin gaignard134100.00%1100.00%
Total134100.00%1100.00%

#define DBGFS_PRINT_STR(str1, str2) seq_printf(s, "%-24s %s\n", str1, str2) #define DBGFS_PRINT_INT(str1, int2) seq_printf(s, "%-24s %d\n", str1, int2) #define DBGFS_DUMP(str, reg) seq_printf(s, "%s %-25s 0x%08X", str, #reg, \ hdmi_read(hdmi, reg)) #define DBGFS_DUMP_DI(reg, slot) DBGFS_DUMP("\n", reg(slot))
static void hdmi_dbg_cfg(struct seq_file *s, int val) { int tmp; seq_puts(s, "\t"); tmp = val & HDMI_CFG_HDMI_NOT_DVI; DBGFS_PRINT_STR("mode:", tmp ? "HDMI" : "DVI"); seq_puts(s, "\t\t\t\t\t"); tmp = val & HDMI_CFG_HDCP_EN; DBGFS_PRINT_STR("HDCP:", tmp ? "enable" : "disable"); seq_puts(s, "\t\t\t\t\t"); tmp = val & HDMI_CFG_ESS_NOT_OESS; DBGFS_PRINT_STR("HDCP mode:", tmp ? "ESS enable" : "OESS enable"); seq_puts(s, "\t\t\t\t\t"); tmp = val & HDMI_CFG_SINK_TERM_DET_EN; DBGFS_PRINT_STR("Sink term detection:", tmp ? "enable" : "disable"); seq_puts(s, "\t\t\t\t\t"); tmp = val & HDMI_CFG_H_SYNC_POL_NEG; DBGFS_PRINT_STR("Hsync polarity:", tmp ? "inverted" : "normal"); seq_puts(s, "\t\t\t\t\t"); tmp = val & HDMI_CFG_V_SYNC_POL_NEG; DBGFS_PRINT_STR("Vsync polarity:", tmp ? "inverted" : "normal"); seq_puts(s, "\t\t\t\t\t"); tmp = val & HDMI_CFG_422_EN; DBGFS_PRINT_STR("YUV422 format:", tmp ? "enable" : "disable"); }

Contributors

PersonTokensPropCommitsCommitProp
vincent abriouvincent abriou14377.30%375.00%
benjamin gaignardbenjamin gaignard4222.70%125.00%
Total185100.00%4100.00%


static void hdmi_dbg_sta(struct seq_file *s, int val) { int tmp; seq_puts(s, "\t"); tmp = (val & HDMI_STA_DLL_LCK); DBGFS_PRINT_STR("pll:", tmp ? "locked" : "not locked"); seq_puts(s, "\t\t\t\t\t"); tmp = (val & HDMI_STA_HOT_PLUG); DBGFS_PRINT_STR("hdmi cable:", tmp ? "connected" : "not connected"); }

Contributors

PersonTokensPropCommitsCommitProp
vincent abriouvincent abriou5782.61%150.00%
benjamin gaignardbenjamin gaignard1217.39%150.00%
Total69100.00%2100.00%


static void hdmi_dbg_sw_di_cfg(struct seq_file *s, int val) { int tmp; char *const en_di[] = {"no transmission", "single transmission", "once every field", "once every frame"}; seq_puts(s, "\t"); tmp = (val & HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, 1)); DBGFS_PRINT_STR("Data island 1:", en_di[tmp]); seq_puts(s, "\t\t\t\t\t"); tmp = (val & HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, 2)) >> 4; DBGFS_PRINT_STR("Data island 2:", en_di[tmp]); seq_puts(s, "\t\t\t\t\t"); tmp = (val & HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, 3)) >> 8; DBGFS_PRINT_STR("Data island 3:", en_di[tmp]); seq_puts(s, "\t\t\t\t\t"); tmp = (val & HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, 4)) >> 12; DBGFS_PRINT_STR("Data island 4:", en_di[tmp]); seq_puts(s, "\t\t\t\t\t"); tmp = (val & HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, 5)) >> 16; DBGFS_PRINT_STR("Data island 5:", en_di[tmp]); seq_puts(s, "\t\t\t\t\t"); tmp = (val & HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, 6)) >> 20; DBGFS_PRINT_STR("Data island 6:", en_di[tmp]); }

Contributors

PersonTokensPropCommitsCommitProp
vincent abriouvincent abriou20792.83%150.00%
benjamin gaignardbenjamin gaignard167.17%150.00%
Total223100.00%2100.00%


static int hdmi_dbg_show(struct seq_file *s, void *data) { struct drm_info_node *node = s->private; struct sti_hdmi *hdmi = (struct sti_hdmi *)node->info_ent->data; struct drm_device *dev = node->minor->dev; int ret; ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; seq_printf(s, "HDMI: (vaddr = 0x%p)", hdmi->regs); DBGFS_DUMP("\n", HDMI_CFG); hdmi_dbg_cfg(s, hdmi_read(hdmi, HDMI_CFG)); DBGFS_DUMP("", HDMI_INT_EN); DBGFS_DUMP("\n", HDMI_STA); hdmi_dbg_sta(s, hdmi_read(hdmi, HDMI_STA)); DBGFS_DUMP("", HDMI_ACTIVE_VID_XMIN); seq_puts(s, "\t"); DBGFS_PRINT_INT("Xmin:", hdmi_read(hdmi, HDMI_ACTIVE_VID_XMIN)); DBGFS_DUMP("", HDMI_ACTIVE_VID_XMAX); seq_puts(s, "\t"); DBGFS_PRINT_INT("Xmax:", hdmi_read(hdmi, HDMI_ACTIVE_VID_XMAX)); DBGFS_DUMP("", HDMI_ACTIVE_VID_YMIN); seq_puts(s, "\t"); DBGFS_PRINT_INT("Ymin:", hdmi_read(hdmi, HDMI_ACTIVE_VID_YMIN)); DBGFS_DUMP("", HDMI_ACTIVE_VID_YMAX); seq_puts(s, "\t"); DBGFS_PRINT_INT("Ymax:", hdmi_read(hdmi, HDMI_ACTIVE_VID_YMAX)); DBGFS_DUMP("", HDMI_SW_DI_CFG); hdmi_dbg_sw_di_cfg(s, hdmi_read(hdmi, HDMI_SW_DI_CFG)); seq_printf(s, "\n AVI Infoframe (Data Island slot N=%d):", HDMI_IFRAME_SLOT_AVI); DBGFS_DUMP_DI(HDMI_SW_DI_N_HEAD_WORD, HDMI_IFRAME_SLOT_AVI); DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD0, HDMI_IFRAME_SLOT_AVI); DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD1, HDMI_IFRAME_SLOT_AVI); DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD2, HDMI_IFRAME_SLOT_AVI); DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD3, HDMI_IFRAME_SLOT_AVI); DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD4, HDMI_IFRAME_SLOT_AVI); DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD5, HDMI_IFRAME_SLOT_AVI); DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD6, HDMI_IFRAME_SLOT_AVI); seq_puts(s, "\n"); seq_printf(s, "\n AUDIO Infoframe (Data Island slot N=%d):", HDMI_IFRAME_SLOT_AUDIO); DBGFS_DUMP_DI(HDMI_SW_DI_N_HEAD_WORD, HDMI_IFRAME_SLOT_AUDIO); DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD0, HDMI_IFRAME_SLOT_AUDIO); DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD1, HDMI_IFRAME_SLOT_AUDIO); DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD2, HDMI_IFRAME_SLOT_AUDIO); DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD3, HDMI_IFRAME_SLOT_AUDIO); DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD4, HDMI_IFRAME_SLOT_AUDIO); DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD5, HDMI_IFRAME_SLOT_AUDIO); DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD6, HDMI_IFRAME_SLOT_AUDIO); seq_puts(s, "\n"); seq_printf(s, "\n VENDOR SPECIFIC Infoframe (Data Island slot N=%d):", HDMI_IFRAME_SLOT_VENDOR); DBGFS_DUMP_DI(HDMI_SW_DI_N_HEAD_WORD, HDMI_IFRAME_SLOT_VENDOR); DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD0, HDMI_IFRAME_SLOT_VENDOR); DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD1, HDMI_IFRAME_SLOT_VENDOR); DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD2, HDMI_IFRAME_SLOT_VENDOR); DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD3, HDMI_IFRAME_SLOT_VENDOR); DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD4, HDMI_IFRAME_SLOT_VENDOR); DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD5, HDMI_IFRAME_SLOT_VENDOR); DBGFS_DUMP_DI(HDMI_SW_DI_N_PKT_WORD6, HDMI_IFRAME_SLOT_VENDOR); seq_puts(s, "\n"); mutex_unlock(&dev->struct_mutex); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
vincent abriouvincent abriou477100.00%1100.00%
Total477100.00%1100.00%

static struct drm_info_list hdmi_debugfs_files[] = { { "hdmi", hdmi_dbg_show, 0, NULL }, };
static void hdmi_debugfs_exit(struct sti_hdmi *hdmi, struct drm_minor *minor) { drm_debugfs_remove_files(hdmi_debugfs_files, ARRAY_SIZE(hdmi_debugfs_files), minor); }

Contributors

PersonTokensPropCommitsCommitProp
vincent abriouvincent abriou28100.00%1100.00%
Total28100.00%1100.00%


static int hdmi_debugfs_init(struct sti_hdmi *hdmi, struct drm_minor *minor) { unsigned int i; for (i = 0; i < ARRAY_SIZE(hdmi_debugfs_files); i++) hdmi_debugfs_files[i].data = hdmi; return drm_debugfs_create_files(hdmi_debugfs_files, ARRAY_SIZE(hdmi_debugfs_files), minor->debugfs_root, minor); }

Contributors

PersonTokensPropCommitsCommitProp
vincent abriouvincent abriou62100.00%1100.00%
Total62100.00%1100.00%


static void sti_hdmi_disable(struct drm_bridge *bridge) { struct sti_hdmi *hdmi = bridge->driver_private; u32 val = hdmi_read(hdmi, HDMI_CFG); if (!hdmi->enabled) return; DRM_DEBUG_DRIVER("\n"); /* Disable HDMI */ val &= ~HDMI_CFG_DEVICE_EN; hdmi_write(hdmi, val, HDMI_CFG); hdmi_write(hdmi, 0xffffffff, HDMI_INT_CLR); /* Stop the phy */ hdmi->phy_ops->stop(hdmi); /* Reset info frame transmission */ hdmi_infoframe_reset(hdmi, HDMI_IFRAME_SLOT_AVI); hdmi_infoframe_reset(hdmi, HDMI_IFRAME_SLOT_AUDIO); hdmi_infoframe_reset(hdmi, HDMI_IFRAME_SLOT_VENDOR); /* Set the default channel data to be a dark red */ hdmi_write(hdmi, 0x0000, HDMI_DFLT_CHL0_DAT); hdmi_write(hdmi, 0x0000, HDMI_DFLT_CHL1_DAT); hdmi_write(hdmi, 0x0060, HDMI_DFLT_CHL2_DAT); /* Disable/unprepare hdmi clock */ clk_disable_unprepare(hdmi->clk_phy); clk_disable_unprepare(hdmi->clk_tmds); clk_disable_unprepare(hdmi->clk_pix); hdmi->enabled = false; }

Contributors

PersonTokensPropCommitsCommitProp
vincent abriouvincent abriou155100.00%1100.00%
Total155100.00%1100.00%


static void sti_hdmi_pre_enable(struct drm_bridge *bridge) { struct sti_hdmi *hdmi = bridge->driver_private; DRM_DEBUG_DRIVER("\n"); if (hdmi->enabled) return; /* Prepare/enable clocks */ if (clk_prepare_enable(hdmi->clk_pix)) DRM_ERROR("Failed to prepare/enable hdmi_pix clk\n"); if (clk_prepare_enable(hdmi->clk_tmds)) DRM_ERROR("Failed to prepare/enable hdmi_tmds clk\n"); if (clk_prepare_enable(hdmi->clk_phy)) DRM_ERROR("Failed to prepare/enable hdmi_rejec_pll clk\n"); hdmi->enabled = true; /* Program hdmi serializer and start phy */ if (!hdmi->phy_ops->start(hdmi)) { DRM_ERROR("Unable to start hdmi phy\n"); return; } /* Program hdmi active area */ hdmi_active_area(hdmi); /* Enable working interrupts */ hdmi_write(hdmi, HDMI_WORKING_INT, HDMI_INT_EN); /* Program hdmi config */ hdmi_config(hdmi); /* Program AVI infoframe */ if (hdmi_avi_infoframe_config(hdmi)) DRM_ERROR("Unable to configure AVI infoframe\n"); /* Program AUDIO infoframe */ if (hdmi_audio_infoframe_config(hdmi)) DRM_ERROR("Unable to configure AUDIO infoframe\n"); /* Program VS infoframe */ if (hdmi_vendor_infoframe_config(hdmi)) DRM_ERROR("Unable to configure VS infoframe\n"); /* Sw reset */ hdmi_swreset(hdmi); }

Contributors

PersonTokensPropCommitsCommitProp
benjamin gaignardbenjamin gaignard9958.58%125.00%
vincent abriouvincent abriou5733.73%250.00%
arnaud pouliquenarnaud pouliquen137.69%125.00%
Total169100.00%4100.00%


static void sti_hdmi_set_mode(struct drm_bridge *bridge, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct sti_hdmi *hdmi = bridge->driver_private; int ret; DRM_DEBUG_DRIVER("\n"); /* Copy the drm display mode in the connector local structure */ memcpy(&hdmi->mode, mode, sizeof(struct drm_display_mode)); /* Update clock framerate according to the selected mode */ ret = clk_set_rate(hdmi->clk_pix, mode->clock * 1000); if (ret < 0) { DRM_ERROR("Cannot set rate (%dHz) for hdmi_pix clk\n", mode->clock * 1000); return; } ret = clk_set_rate(hdmi->clk_phy, mode->clock * 1000); if (ret < 0) { DRM_ERROR("Cannot set rate (%dHz) for hdmi_rejection_pll clk\n", mode->clock * 1000); return; } }

Contributors

PersonTokensPropCommitsCommitProp
benjamin gaignardbenjamin gaignard126100.00%1100.00%
Total126100.00%1100.00%


static void sti_hdmi_bridge_nope(struct drm_bridge *bridge) { /* do nothing */ }

Contributors

PersonTokensPropCommitsCommitProp
benjamin gaignardbenjamin gaignard12100.00%1100.00%
Total12100.00%1100.00%

static const struct drm_bridge_funcs sti_hdmi_bridge_funcs = { .pre_enable = sti_hdmi_pre_enable, .enable = sti_hdmi_bridge_nope, .disable = sti_hdmi_disable, .post_disable = sti_hdmi_bridge_nope, .mode_set = sti_hdmi_set_mode, };
static int sti_hdmi_connector_get_modes(struct drm_connector *connector) { struct sti_hdmi_connector *hdmi_connector = to_sti_hdmi_connector(connector); struct sti_hdmi *hdmi = hdmi_connector->hdmi; struct edid *edid; int count; DRM_DEBUG_DRIVER("\n"); edid = drm_get_edid(connector, hdmi->ddc_adapt); if (!edid) goto fail; count = drm_add_edid_modes(connector, edid); drm_mode_connector_update_edid_property(connector, edid); kfree(edid); return count; fail: DRM_ERROR("Can't read HDMI EDID\n"); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
benjamin gaignardbenjamin gaignard9598.96%266.67%
vincent abriouvincent abriou11.04%133.33%
Total96100.00%3100.00%

#define CLK_TOLERANCE_HZ 50
static int sti_hdmi_connector_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { int target = mode->clock * 1000; int target_min = target - CLK_TOLERANCE_HZ; int target_max = target + CLK_TOLERANCE_HZ; int result; struct sti_hdmi_connector *hdmi_connector = to_sti_hdmi_connector(connector); struct sti_hdmi *hdmi = hdmi_connector->hdmi; result = clk_round_rate(hdmi->clk_pix, target); DRM_DEBUG_DRIVER("target rate = %d => available rate = %d\n", target, result); if ((result < target_min) || (result > target_max)) { DRM_DEBUG_DRIVER("hdmi pixclk=%d not supported\n", target); return MODE_BAD; } return MODE_OK; }

Contributors

PersonTokensPropCommitsCommitProp
benjamin gaignardbenjamin gaignard110100.00%1100.00%
Total110100.00%1100.00%


struct drm_encoder *sti_hdmi_best_encoder(struct drm_connector *connector) { struct sti_hdmi_connector *hdmi_connector = to_sti_hdmi_connector(connector); /* Best encoder is the one associated during connector creation */ return hdmi_connector->encoder; }

Contributors

PersonTokensPropCommitsCommitProp
benjamin gaignardbenjamin gaignard28100.00%1100.00%
Total28100.00%1100.00%

static const struct drm_connector_helper_funcs sti_hdmi_connector_helper_funcs = { .get_modes = sti_hdmi_connector_get_modes, .mode_valid = sti_hdmi_connector_mode_valid, .best_encoder = sti_hdmi_best_encoder, }; /* get detection status of display device */
static enum drm_connector_status sti_hdmi_connector_detect(struct drm_connector *connector, bool force) { struct sti_hdmi_connector *hdmi_connector = to_sti_hdmi_connector(connector); struct sti_hdmi *hdmi = hdmi_connector->hdmi; DRM_DEBUG_DRIVER("\n"); if (hdmi->hpd) { DRM_DEBUG_DRIVER("hdmi cable connected\n"); return connector_status_connected; } DRM_DEBUG_DRIVER("hdmi cable disconnected\n"); return connector_status_disconnected; }

Contributors

PersonTokensPropCommitsCommitProp
benjamin gaignardbenjamin gaignard63100.00%1100.00%
Total63100.00%1100.00%


static void sti_hdmi_connector_destroy(struct drm_connector *connector) { struct sti_hdmi_connector *hdmi_connector = to_sti_hdmi_connector(connector); drm_connector_unregister(connector); drm_connector_cleanup(connector); kfree(hdmi_connector); }

Contributors

PersonTokensPropCommitsCommitProp
benjamin gaignardbenjamin gaignard36100.00%1100.00%
Total36100.00%1100.00%


static void sti_hdmi_connector_init_property(struct drm_device *drm_dev, struct drm_connector *connector) { struct sti_hdmi_connector *hdmi_connector = to_sti_hdmi_connector(connector); struct sti_hdmi *hdmi = hdmi_connector->hdmi; struct drm_property *prop; /* colorspace property */ hdmi->colorspace = DEFAULT_COLORSPACE_MODE; prop = drm_property_create_enum(drm_dev, 0, "colorspace", colorspace_mode_names, ARRAY_SIZE(colorspace_mode_names)); if (!prop) { DRM_ERROR("fails to create colorspace property\n"); return; } hdmi_connector->colorspace_property = prop; drm_object_attach_property(&connector->base, prop, hdmi->colorspace); /* hdmi_mode property */ hdmi->hdmi_mode = DEFAULT_HDMI_MODE; prop = drm_property_create_enum(drm_dev, 0, "hdmi_mode", hdmi_mode_names, ARRAY_SIZE(hdmi_mode_names)); if (!prop) { DRM_ERROR("fails to create colorspace property\n"); return; } hdmi_connector->hdmi_mode_property = prop; drm_object_attach_property(&connector->base, prop, hdmi->hdmi_mode); }

Contributors

PersonTokensPropCommitsCommitProp
vincent abriouvincent abriou156100.00%2100.00%
Total156100.00%2100.00%


static int sti_hdmi_connector_set_property(struct drm_connector *connector, struct drm_connector_state *state, struct drm_property *property, uint64_t val) { struct sti_hdmi_connector *hdmi_connector = to_sti_hdmi_connector(connector); struct sti_hdmi *hdmi = hdmi_connector->hdmi; if (property == hdmi_connector->colorspace_property) { hdmi->colorspace = val; return 0; } if (property == hdmi_connector->hdmi_mode_property) { hdmi->hdmi_mode = val; return 0; } DRM_ERROR("failed to set hdmi connector property\n"); return -EINVAL; }

Contributors

PersonTokensPropCommitsCommitProp
vincent abriouvincent abriou90100.00%2100.00%
Total90100.00%2100.00%


static int sti_hdmi_connector_get_property(struct drm_connector *connector, const struct drm_connector_state *state, struct drm_property *property, uint64_t *val) { struct sti_hdmi_connector *hdmi_connector = to_sti_hdmi_connector(connector); struct sti_hdmi *hdmi = hdmi_connector->hdmi; if (property == hdmi_connector->colorspace_property) { *val = hdmi->colorspace; return 0; } if (property == hdmi_connector->hdmi_mode_property) { *val = hdmi->hdmi_mode; return 0; } DRM_ERROR("failed to get hdmi connector property\n"); return -EINVAL; }

Contributors

PersonTokensPropCommitsCommitProp
vincent abriouvincent abriou94100.00%2100.00%
Total94100.00%2100.00%

static const struct drm_connector_funcs sti_hdmi_connector_funcs = { .dpms = drm_atomic_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = sti_hdmi_connector_detect, .destroy = sti_hdmi_connector_destroy, .reset = drm_atomic_helper_connector_reset, .set_property = drm_atomic_helper_connector_set_property, .atomic_set_property = sti_hdmi_connector_set_property, .atomic_get_property = sti_hdmi_connector_get_property, .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, };
static struct drm_encoder *sti_hdmi_find_encoder(struct drm_device *dev) { struct drm_encoder *encoder; list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { if (encoder->encoder_type == DRM_MODE_ENCODER_TMDS) return encoder; } return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
benjamin gaignardbenjamin gaignard42100.00%1100.00%
Total42100.00%1100.00%


static int sti_hdmi_bind(struct device *dev, struct device *master, void *data) { struct sti_hdmi *hdmi = dev_get_drvdata(dev); struct drm_device *drm_dev = data; struct drm_encoder *encoder; struct sti_hdmi_connector *connector; struct drm_connector *drm_connector; struct drm_bridge *bridge; int err; /* Set the drm device handle */ hdmi->drm_dev = drm_dev; encoder = sti_hdmi_find_encoder(drm_dev); if (!encoder) return -EINVAL; connector = devm_kzalloc(dev, sizeof(*connector), GFP_KERNEL); if (!connector) return -EINVAL; connector->hdmi = hdmi; bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL); if (!bridge) return -EINVAL; bridge->driver_private = hdmi; bridge->funcs = &sti_hdmi_bridge_funcs; drm_bridge_attach(drm_dev, bridge); encoder->bridge = bridge; connector->encoder = encoder; drm_connector = (struct drm_connector *)connector; drm_connector->polled = DRM_CONNECTOR_POLL_HPD; drm_connector_init(drm_dev, drm_connector, &sti_hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA); drm_connector_helper_add(drm_connector, &sti_hdmi_connector_helper_funcs); /* initialise property */ sti_hdmi_connector_init_property(drm_dev, drm_connector); err = drm_connector_register(drm_connector); if (err) goto err_connector; err = drm_mode_connector_attach_encoder(drm_connector, encoder); if (err) { DRM_ERROR("Failed to attach a connector to a encoder\n"); goto err_sysfs; } /* Enable default interrupts */ hdmi_write(hdmi, HDMI_DEFAULT_INT, HDMI_INT_EN); if (hdmi_debugfs_init(hdmi, drm_dev->primary)) DRM_ERROR("HDMI debugfs setup failed\n"); return 0; err_sysfs: drm_connector_unregister(drm_connector); err_connector: drm_connector_cleanup(drm_connector); return -EINVAL; }

Contributors

PersonTokensPropCommitsCommitProp
benjamin gaignardbenjamin gaignard25285.14%116.67%
vincent abriouvincent abriou248.11%233.33%
vladimir zapolskiyvladimir zapolskiy124.05%116.67%
ajay kumarajay kumar82.70%233.33%
Total296100.00%6100.00%


static void sti_hdmi_unbind(struct device *dev, struct device *master, void *data) { struct sti_hdmi *hdmi = dev_get_drvdata(dev); struct drm_device *drm_dev = data; hdmi_debugfs_exit(hdmi, drm_dev->primary); }

Contributors

PersonTokensPropCommitsCommitProp
vincent abriouvincent abriou2656.52%150.00%
benjamin gaignardbenjamin gaignard2043.48%150.00%
Total46100.00%2100.00%

static const struct component_ops sti_hdmi_ops = { .bind = sti_hdmi_bind, .unbind = sti_hdmi_unbind, }; static const struct of_device_id hdmi_of_match[] = { { .compatible = "st,stih416-hdmi", .data = &tx3g0c55phy_ops, }, { .compatible = "st,stih407-hdmi", .data = &tx3g4c28phy_ops, }, { /* end node */ } }; MODULE_DEVICE_TABLE(of, hdmi_of_match);
static int sti_hdmi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct sti_hdmi *hdmi; struct device_node *np = dev->of_node; struct resource *res; struct device_node *ddc; int ret; DRM_INFO("%s\n", __func__); hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL); if (!hdmi) return -ENOMEM; ddc = of_parse_phandle(pdev->dev.of_node, "ddc", 0); if (ddc) { hdmi->ddc_adapt = of_get_i2c_adapter_by_node(ddc); of_node_put(ddc); if (!hdmi->ddc_adapt) return -EPROBE_DEFER; } hdmi->dev = pdev->dev; /* Get resources */ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hdmi-reg"); if (!res) { DRM_ERROR("Invalid hdmi resource\n"); ret = -ENOMEM; goto release_adapter; } hdmi->regs = devm_ioremap_nocache(dev, res->start, resource_size(res)); if (!hdmi->regs) { ret = -ENOMEM; goto release_adapter; } if (of_device_is_compatible(np, "st,stih416-hdmi")) { res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "syscfg"); if (!res) { DRM_ERROR("Invalid syscfg resource\n"); ret = -ENOMEM; goto release_adapter; } hdmi->syscfg = devm_ioremap_nocache(dev, res->start, resource_size(res)); if (!hdmi->syscfg) { ret = -ENOMEM; goto release_adapter; } } hdmi->phy_ops = (struct hdmi_phy_ops *) of_match_node(hdmi_of_match, np)->data; /* Get clock resources */ hdmi->clk_pix = devm_clk_get(dev, "pix"); if (IS_ERR(hdmi->clk_pix)) { DRM_ERROR("Cannot get hdmi_pix clock\n"); ret = PTR_ERR(hdmi->clk_pix); goto release_adapter; } hdmi->clk_tmds = devm_clk_get(dev, "tmds"); if (IS_ERR(hdmi->clk_tmds)) { DRM_ERROR("Cannot get hdmi_tmds clock\n"); ret = PTR_ERR(hdmi->clk_tmds); goto release_adapter; } hdmi->clk_phy = devm_clk_get(dev, "phy"); if (IS_ERR(hdmi->clk_phy)) { DRM_ERROR("Cannot get hdmi_phy clock\n"); ret = PTR_ERR(hdmi->clk_phy); goto release_adapter; } hdmi->clk_audio = devm_clk_get(dev, "audio"); if (IS_ERR(hdmi->clk_audio)) { DRM_ERROR("Cannot get hdmi_audio clock\n"); ret = PTR_ERR(hdmi->clk_audio); goto release_adapter; } hdmi->hpd = readl(hdmi->regs + HDMI_STA) & HDMI_STA_HOT_PLUG; init_waitqueue_head(&hdmi->wait_event); hdmi->irq = platform_get_irq_byname(pdev, "irq"); ret = devm_request_threaded_irq(dev, hdmi->irq, hdmi_irq, hdmi_irq_thread, IRQF_ONESHOT, dev_name(dev), hdmi); if (ret) { DRM_ERROR("Failed to register HDMI interrupt\n"); goto release_adapter; } hdmi->reset = devm_reset_control_get(dev, "hdmi"); /* Take hdmi out of reset */ if (!IS_ERR(hdmi->reset)) reset_control_deassert(hdmi->reset); platform_set_drvdata(pdev, hdmi); return component_add(&pdev->dev, &sti_hdmi_ops); release_adapter: i2c_put_adapter(hdmi->ddc_adapt); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
benjamin gaignardbenjamin gaignard50586.47%350.00%
vladimir zapolskiyvladimir zapolskiy7312.50%233.33%
wei yongjunwei yongjun61.03%116.67%
Total584100.00%6100.00%


static int sti_hdmi_remove(struct platform_device *pdev) { struct sti_hdmi *hdmi = dev_get_drvdata(&pdev->dev); i2c_put_adapter(hdmi->ddc_adapt); component_del(&pdev->dev, &sti_hdmi_ops); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
benjamin gaignardbenjamin gaignard4497.78%266.67%
vladimir zapolskiyvladimir zapolskiy12.22%133.33%
Total45100.00%3100.00%

struct platform_driver sti_hdmi_driver = { .driver = { .name = "sti-hdmi", .owner = THIS_MODULE, .of_match_table = hdmi_of_match, }, .probe = sti_hdmi_probe, .remove = sti_hdmi_remove, }; MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>"); MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver"); MODULE_LICENSE("GPL");

Overall Contributors

PersonTokensPropCommitsCommitProp
benjamin gaignardbenjamin gaignard275651.29%523.81%
vincent abriouvincent abriou203137.80%838.10%
arnaud pouliquenarnaud pouliquen4838.99%14.76%
vladimir zapolskiyvladimir zapolskiy861.60%29.52%
ajay kumarajay kumar80.15%29.52%
wei yongjunwei yongjun60.11%14.76%
ville syrjalaville syrjala20.04%14.76%
kiran padwalkiran padwal10.02%14.76%
Total5373100.00%21100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}