#include "regs-hdmi.h"
#include <linux/kernel.h>
-#include <linux/spinlock.h>
#include <linux/wait.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/regulator/consumer.h>
#include <linux/io.h>
-#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/hdmi.h>
#include <linux/component.h>
#include "exynos_mixer.h"
#include <linux/gpio.h>
-#include <media/s5p_hdmi.h>
#define ctx_from_connector(c) container_of(c, struct hdmi_context, connector)
u8 tg_3d[1];
};
-struct hdmi_v13_core_regs {
- u8 h_blank[2];
- u8 v_blank[3];
- u8 h_v_line[3];
- u8 vsync_pol[1];
- u8 int_pro_mode[1];
- u8 v_blank_f[3];
- u8 h_sync_gen[3];
- u8 v_sync_gen1[3];
- u8 v_sync_gen2[3];
- u8 v_sync_gen3[3];
-};
-
struct hdmi_v14_core_regs {
u8 h_blank[2];
u8 v2_blank[2];
u8 vact_space_6[2];
};
-struct hdmi_v13_conf {
- struct hdmi_v13_core_regs core;
- struct hdmi_tg_regs tg;
-};
-
struct hdmi_v14_conf {
struct hdmi_v14_core_regs core;
struct hdmi_tg_regs tg;
};
-struct hdmi_conf_regs {
- int pixel_clock;
- int cea_video_id;
- enum hdmi_picture_aspect aspect_ratio;
- union {
- struct hdmi_v13_conf v13_conf;
- struct hdmi_v14_conf v14_conf;
- } conf;
-};
-
struct hdmi_context {
struct exynos_drm_display display;
struct device *dev;
struct drm_device *drm_dev;
struct drm_connector connector;
struct drm_encoder *encoder;
- bool hpd;
bool powered;
bool dvi_mode;
- struct mutex hdmi_mutex;
void __iomem *regs;
int irq;
/* current hdmiphy conf regs */
struct drm_display_mode current_mode;
- struct hdmi_conf_regs mode_conf;
+ u8 cea_video_id;
+ struct hdmi_v14_conf mode_conf;
struct hdmi_resources res;
+ const struct hdmi_driver_data *drv_data;
int hpd_gpio;
void __iomem *regs_hdmiphy;
- const struct hdmiphy_config *phy_confs;
- unsigned int phy_conf_count;
struct regmap *pmureg;
- enum hdmi_type type;
};
static inline struct hdmi_context *display_to_hdmi(struct exynos_drm_display *d)
writeb(value, hdata->regs + reg_id);
}
+static inline void hdmi_reg_writev(struct hdmi_context *hdata, u32 reg_id,
+ int bytes, u32 val)
+{
+ while (--bytes >= 0) {
+ writeb(val & 0xff, hdata->regs + reg_id);
+ val >>= 8;
+ reg_id += 4;
+ }
+}
+
static inline void hdmi_reg_writemask(struct hdmi_context *hdata,
u32 reg_id, u32 value, u32 mask)
{
static void hdmi_regs_dump(struct hdmi_context *hdata, char *prefix)
{
- if (hdata->type == HDMI_TYPE13)
+ if (hdata->drv_data->type == HDMI_TYPE13)
hdmi_v13_regs_dump(hdata, prefix);
else
hdmi_v14_regs_dump(hdata, prefix);
u32 hdr_sum;
u8 chksum;
u32 mod;
- u32 vic;
+ u8 ar;
mod = hdmi_reg_read(hdata, HDMI_MODE_SEL);
if (hdata->dvi_mode) {
* Set the aspect ratio as per the mode, mentioned in
* Table 9 AVI InfoFrame Data Byte 2 of CEA-861-D Standard
*/
- switch (hdata->mode_conf.aspect_ratio) {
+ ar = hdata->current_mode.picture_aspect_ratio;
+ switch (ar) {
case HDMI_PICTURE_ASPECT_4_3:
- hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
- hdata->mode_conf.aspect_ratio |
- AVI_4_3_CENTER_RATIO);
+ ar |= AVI_4_3_CENTER_RATIO;
break;
case HDMI_PICTURE_ASPECT_16_9:
- hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
- hdata->mode_conf.aspect_ratio |
- AVI_16_9_CENTER_RATIO);
+ ar |= AVI_16_9_CENTER_RATIO;
break;
case HDMI_PICTURE_ASPECT_NONE:
default:
- hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
- hdata->mode_conf.aspect_ratio |
- AVI_SAME_AS_PIC_ASPECT_RATIO);
+ ar |= AVI_SAME_AS_PIC_ASPECT_RATIO;
break;
}
+ hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2), ar);
- vic = hdata->mode_conf.cea_video_id;
- hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), vic);
+ hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), hdata->cea_video_id);
chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1),
infoframe->any.length, hdr_sum);
{
struct hdmi_context *hdata = ctx_from_connector(connector);
- hdata->hpd = gpio_get_value(hdata->hpd_gpio);
+ if (gpio_get_value(hdata->hpd_gpio))
+ return connector_status_connected;
- return hdata->hpd ? connector_status_connected :
- connector_status_disconnected;
+ return connector_status_disconnected;
}
static void hdmi_connector_destroy(struct drm_connector *connector)
{
struct hdmi_context *hdata = ctx_from_connector(connector);
struct edid *edid;
+ int ret;
if (!hdata->ddc_adpt)
return -ENODEV;
drm_mode_connector_update_edid_property(connector, edid);
- return drm_add_edid_modes(connector, edid);
+ ret = drm_add_edid_modes(connector, edid);
+
+ kfree(edid);
+
+ return ret;
}
static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
{
int i;
- for (i = 0; i < hdata->phy_conf_count; i++)
- if (hdata->phy_confs[i].pixel_clock == pixel_clock)
+ for (i = 0; i < hdata->drv_data->phy_conf_count; i++)
+ if (hdata->drv_data->phy_confs[i].pixel_clock == pixel_clock)
return i;
DRM_DEBUG_KMS("Could not find phy config for %d\n", pixel_clock);
hdmi_reg_writeb(hdata, HDMI_ACR_CTS1, acr[2]);
hdmi_reg_writeb(hdata, HDMI_ACR_CTS2, acr[1]);
- if (hdata->type == HDMI_TYPE13)
+ if (hdata->drv_data->type == HDMI_TYPE13)
hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 4);
else
hdmi_reg_writeb(hdata, HDMI_ACR_CON, 4);
HDMI_VID_PREAMBLE_DIS | HDMI_GUARD_BAND_DIS);
}
- if (hdata->type == HDMI_TYPE13) {
+ if (hdata->drv_data->type == HDMI_TYPE13) {
/* choose bluescreen (fecal) color */
hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_0, 0x12);
hdmi_reg_writeb(hdata, HDMI_V13_BLUE_SCREEN_1, 0x34);
static void hdmi_v13_mode_apply(struct hdmi_context *hdata)
{
- const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
- const struct hdmi_v13_core_regs *core =
- &hdata->mode_conf.conf.v13_conf.core;
+ struct drm_display_mode *m = &hdata->current_mode;
+ unsigned int val;
int tries;
- /* setting core registers */
- hdmi_reg_writeb(hdata, HDMI_H_BLANK_0, core->h_blank[0]);
- hdmi_reg_writeb(hdata, HDMI_H_BLANK_1, core->h_blank[1]);
- hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_0, core->v_blank[0]);
- hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_1, core->v_blank[1]);
- hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_2, core->v_blank[2]);
- hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_0, core->h_v_line[0]);
- hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_1, core->h_v_line[1]);
- hdmi_reg_writeb(hdata, HDMI_V13_H_V_LINE_2, core->h_v_line[2]);
- hdmi_reg_writeb(hdata, HDMI_VSYNC_POL, core->vsync_pol[0]);
- hdmi_reg_writeb(hdata, HDMI_INT_PRO_MODE, core->int_pro_mode[0]);
- hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_0, core->v_blank_f[0]);
- hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_1, core->v_blank_f[1]);
- hdmi_reg_writeb(hdata, HDMI_V13_V_BLANK_F_2, core->v_blank_f[2]);
- hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_0, core->h_sync_gen[0]);
- hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_1, core->h_sync_gen[1]);
- hdmi_reg_writeb(hdata, HDMI_V13_H_SYNC_GEN_2, core->h_sync_gen[2]);
- hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_0, core->v_sync_gen1[0]);
- hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_1, core->v_sync_gen1[1]);
- hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_1_2, core->v_sync_gen1[2]);
- hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_0, core->v_sync_gen2[0]);
- hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_1, core->v_sync_gen2[1]);
- hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_2_2, core->v_sync_gen2[2]);
- hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_0, core->v_sync_gen3[0]);
- hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_1, core->v_sync_gen3[1]);
- hdmi_reg_writeb(hdata, HDMI_V13_V_SYNC_GEN_3_2, core->v_sync_gen3[2]);
+ hdmi_reg_writev(hdata, HDMI_H_BLANK_0, 2, m->htotal - m->hdisplay);
+ hdmi_reg_writev(hdata, HDMI_V13_H_V_LINE_0, 3,
+ (m->htotal << 12) | m->vtotal);
+
+ val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
+ hdmi_reg_writev(hdata, HDMI_VSYNC_POL, 1, val);
+
+ val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0;
+ hdmi_reg_writev(hdata, HDMI_INT_PRO_MODE, 1, val);
+
+ val = (m->hsync_start - m->hdisplay - 2);
+ val |= ((m->hsync_end - m->hdisplay - 2) << 10);
+ val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20;
+ hdmi_reg_writev(hdata, HDMI_V13_H_SYNC_GEN_0, 3, val);
+
+ /*
+ * Quirk requirement for exynos HDMI IP design,
+ * 2 pixels less than the actual calculation for hsync_start
+ * and end.
+ */
+
+ /* Following values & calculations differ for different type of modes */
+ if (m->flags & DRM_MODE_FLAG_INTERLACE) {
+ /* Interlaced Mode */
+ val = ((m->vsync_end - m->vdisplay) / 2);
+ val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
+ hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val);
+
+ val = m->vtotal / 2;
+ val |= ((m->vtotal - m->vdisplay) / 2) << 11;
+ hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val);
+
+ val = (m->vtotal +
+ ((m->vsync_end - m->vsync_start) * 4) + 5) / 2;
+ val |= m->vtotal << 11;
+ hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, val);
+
+ val = ((m->vtotal / 2) + 7);
+ val |= ((m->vtotal / 2) + 2) << 12;
+ hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, val);
+
+ val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay));
+ val |= ((m->htotal / 2) +
+ (m->hsync_start - m->hdisplay)) << 12;
+ hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, val);
+
+ hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
+ (m->vtotal - m->vdisplay) / 2);
+ hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay / 2);
+
+ hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x249);
+ } else {
+ /* Progressive Mode */
+
+ val = m->vtotal;
+ val |= (m->vtotal - m->vdisplay) << 11;
+ hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_0, 3, val);
+
+ hdmi_reg_writev(hdata, HDMI_V13_V_BLANK_F_0, 3, 0);
+
+ val = (m->vsync_end - m->vdisplay);
+ val |= ((m->vsync_start - m->vdisplay) << 12);
+ hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_1_0, 3, val);
+
+ hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_2_0, 3, 0x1001);
+ hdmi_reg_writev(hdata, HDMI_V13_V_SYNC_GEN_3_0, 3, 0x1001);
+ hdmi_reg_writev(hdata, HDMI_TG_VACT_ST_L, 2,
+ m->vtotal - m->vdisplay);
+ hdmi_reg_writev(hdata, HDMI_TG_VACT_SZ_L, 2, m->vdisplay);
+ hdmi_reg_writev(hdata, HDMI_TG_VACT_ST2_L, 2, 0x248);
+ }
+
/* Timing generator registers */
- hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_L, tg->h_fsz[0]);
- hdmi_reg_writeb(hdata, HDMI_TG_H_FSZ_H, tg->h_fsz[1]);
- hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_L, tg->hact_st[0]);
- hdmi_reg_writeb(hdata, HDMI_TG_HACT_ST_H, tg->hact_st[1]);
- hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_L, tg->hact_sz[0]);
- hdmi_reg_writeb(hdata, HDMI_TG_HACT_SZ_H, tg->hact_sz[1]);
- hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_L, tg->v_fsz[0]);
- hdmi_reg_writeb(hdata, HDMI_TG_V_FSZ_H, tg->v_fsz[1]);
- hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_L, tg->vsync[0]);
- hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_H, tg->vsync[1]);
- hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_L, tg->vsync2[0]);
- hdmi_reg_writeb(hdata, HDMI_TG_VSYNC2_H, tg->vsync2[1]);
- hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_L, tg->vact_st[0]);
- hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST_H, tg->vact_st[1]);
- hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_L, tg->vact_sz[0]);
- hdmi_reg_writeb(hdata, HDMI_TG_VACT_SZ_H, tg->vact_sz[1]);
- hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_L, tg->field_chg[0]);
- hdmi_reg_writeb(hdata, HDMI_TG_FIELD_CHG_H, tg->field_chg[1]);
- hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_L, tg->vact_st2[0]);
- hdmi_reg_writeb(hdata, HDMI_TG_VACT_ST2_H, tg->vact_st2[1]);
- hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, tg->vsync_top_hdmi[0]);
- hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_TOP_HDMI_H, tg->vsync_top_hdmi[1]);
- hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, tg->vsync_bot_hdmi[0]);
- hdmi_reg_writeb(hdata, HDMI_TG_VSYNC_BOT_HDMI_H, tg->vsync_bot_hdmi[1]);
- hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_L, tg->field_top_hdmi[0]);
- hdmi_reg_writeb(hdata, HDMI_TG_FIELD_TOP_HDMI_H, tg->field_top_hdmi[1]);
- hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_L, tg->field_bot_hdmi[0]);
- hdmi_reg_writeb(hdata, HDMI_TG_FIELD_BOT_HDMI_H, tg->field_bot_hdmi[1]);
+ hdmi_reg_writev(hdata, HDMI_TG_H_FSZ_L, 2, m->htotal);
+ hdmi_reg_writev(hdata, HDMI_TG_HACT_ST_L, 2, m->htotal - m->hdisplay);
+ hdmi_reg_writev(hdata, HDMI_TG_HACT_SZ_L, 2, m->hdisplay);
+ hdmi_reg_writev(hdata, HDMI_TG_V_FSZ_L, 2, m->vtotal);
+ hdmi_reg_writev(hdata, HDMI_TG_VSYNC_L, 2, 0x1);
+ hdmi_reg_writev(hdata, HDMI_TG_VSYNC2_L, 2, 0x233);
+ hdmi_reg_writev(hdata, HDMI_TG_FIELD_CHG_L, 2, 0x233);
+ hdmi_reg_writev(hdata, HDMI_TG_VSYNC_TOP_HDMI_L, 2, 0x1);
+ hdmi_reg_writev(hdata, HDMI_TG_VSYNC_BOT_HDMI_L, 2, 0x233);
+ hdmi_reg_writev(hdata, HDMI_TG_FIELD_TOP_HDMI_L, 2, 0x1);
+ hdmi_reg_writev(hdata, HDMI_TG_FIELD_BOT_HDMI_L, 2, 0x233);
/* waiting for HDMIPHY's PLL to get to steady state */
for (tries = 100; tries; --tries) {
static void hdmi_v14_mode_apply(struct hdmi_context *hdata)
{
- const struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
- const struct hdmi_v14_core_regs *core =
- &hdata->mode_conf.conf.v14_conf.core;
+ const struct hdmi_tg_regs *tg = &hdata->mode_conf.tg;
+ const struct hdmi_v14_core_regs *core = &hdata->mode_conf.core;
int tries;
/* setting core registers */
static void hdmi_mode_apply(struct hdmi_context *hdata)
{
- if (hdata->type == HDMI_TYPE13)
+ if (hdata->drv_data->type == HDMI_TYPE13)
hdmi_v13_mode_apply(hdata);
else
hdmi_v14_mode_apply(hdata);
hdmiphy_reg_writeb(hdata, HDMIPHY_MODE_SET_DONE,
HDMI_PHY_ENABLE_MODE_SET);
- if (hdata->type == HDMI_TYPE13)
+ if (hdata->drv_data->type == HDMI_TYPE13)
reg = HDMI_V13_PHY_RSTOUT;
else
reg = HDMI_PHY_RSTOUT;
static void hdmiphy_poweron(struct hdmi_context *hdata)
{
- if (hdata->type != HDMI_TYPE14)
+ if (hdata->drv_data->type != HDMI_TYPE14)
return;
DRM_DEBUG_KMS("\n");
static void hdmiphy_poweroff(struct hdmi_context *hdata)
{
- if (hdata->type != HDMI_TYPE14)
+ if (hdata->drv_data->type != HDMI_TYPE14)
return;
DRM_DEBUG_KMS("\n");
int i;
/* pixel clock */
- i = hdmi_find_phy_conf(hdata, hdata->mode_conf.pixel_clock);
+ i = hdmi_find_phy_conf(hdata, hdata->current_mode.clock * 1000);
if (i < 0) {
DRM_ERROR("failed to find hdmiphy conf\n");
return;
}
- ret = hdmiphy_reg_write_buf(hdata, 0, hdata->phy_confs[i].conf, 32);
+ ret = hdmiphy_reg_write_buf(hdata, 0,
+ hdata->drv_data->phy_confs[i].conf, 32);
if (ret) {
DRM_ERROR("failed to configure hdmiphy\n");
return;
hdmiphy_conf_reset(hdata);
hdmiphy_conf_apply(hdata);
- mutex_lock(&hdata->hdmi_mutex);
hdmi_start(hdata, false);
hdmi_conf_init(hdata);
- mutex_unlock(&hdata->hdmi_mutex);
hdmi_audio_init(hdata);
reg_pair[i] = (value >> (8 * i)) & 0xff;
}
-static void hdmi_v13_mode_set(struct hdmi_context *hdata,
- struct drm_display_mode *m)
-{
- struct hdmi_v13_core_regs *core = &hdata->mode_conf.conf.v13_conf.core;
- struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v13_conf.tg;
- unsigned int val;
-
- hdata->mode_conf.cea_video_id =
- drm_match_cea_mode((struct drm_display_mode *)m);
- hdata->mode_conf.pixel_clock = m->clock * 1000;
- hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio;
-
- hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
- hdmi_set_reg(core->h_v_line, 3, (m->htotal << 12) | m->vtotal);
-
- val = (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0;
- hdmi_set_reg(core->vsync_pol, 1, val);
-
- val = (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0;
- hdmi_set_reg(core->int_pro_mode, 1, val);
-
- val = (m->hsync_start - m->hdisplay - 2);
- val |= ((m->hsync_end - m->hdisplay - 2) << 10);
- val |= ((m->flags & DRM_MODE_FLAG_NHSYNC) ? 1 : 0)<<20;
- hdmi_set_reg(core->h_sync_gen, 3, val);
-
- /*
- * Quirk requirement for exynos HDMI IP design,
- * 2 pixels less than the actual calculation for hsync_start
- * and end.
- */
-
- /* Following values & calculations differ for different type of modes */
- if (m->flags & DRM_MODE_FLAG_INTERLACE) {
- /* Interlaced Mode */
- val = ((m->vsync_end - m->vdisplay) / 2);
- val |= ((m->vsync_start - m->vdisplay) / 2) << 12;
- hdmi_set_reg(core->v_sync_gen1, 3, val);
-
- val = m->vtotal / 2;
- val |= ((m->vtotal - m->vdisplay) / 2) << 11;
- hdmi_set_reg(core->v_blank, 3, val);
-
- val = (m->vtotal +
- ((m->vsync_end - m->vsync_start) * 4) + 5) / 2;
- val |= m->vtotal << 11;
- hdmi_set_reg(core->v_blank_f, 3, val);
-
- val = ((m->vtotal / 2) + 7);
- val |= ((m->vtotal / 2) + 2) << 12;
- hdmi_set_reg(core->v_sync_gen2, 3, val);
-
- val = ((m->htotal / 2) + (m->hsync_start - m->hdisplay));
- val |= ((m->htotal / 2) +
- (m->hsync_start - m->hdisplay)) << 12;
- hdmi_set_reg(core->v_sync_gen3, 3, val);
-
- hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
- hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
-
- hdmi_set_reg(tg->vact_st2, 2, 0x249);/* Reset value + 1*/
- } else {
- /* Progressive Mode */
-
- val = m->vtotal;
- val |= (m->vtotal - m->vdisplay) << 11;
- hdmi_set_reg(core->v_blank, 3, val);
-
- hdmi_set_reg(core->v_blank_f, 3, 0);
-
- val = (m->vsync_end - m->vdisplay);
- val |= ((m->vsync_start - m->vdisplay) << 12);
- hdmi_set_reg(core->v_sync_gen1, 3, val);
-
- hdmi_set_reg(core->v_sync_gen2, 3, 0x1001);/* Reset value */
- hdmi_set_reg(core->v_sync_gen3, 3, 0x1001);/* Reset value */
- hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
- hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
- hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
- }
-
- /* Timing generator registers */
- hdmi_set_reg(tg->cmd, 1, 0x0);
- hdmi_set_reg(tg->h_fsz, 2, m->htotal);
- hdmi_set_reg(tg->hact_st, 2, m->htotal - m->hdisplay);
- hdmi_set_reg(tg->hact_sz, 2, m->hdisplay);
- hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
- hdmi_set_reg(tg->vsync, 2, 0x1);
- hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
- hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
- hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
- hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
- hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
- hdmi_set_reg(tg->field_bot_hdmi, 2, 0x233); /* Reset value */
- hdmi_set_reg(tg->tg_3d, 1, 0x0); /* Not used */
-}
-
static void hdmi_v14_mode_set(struct hdmi_context *hdata,
struct drm_display_mode *m)
{
- struct hdmi_tg_regs *tg = &hdata->mode_conf.conf.v14_conf.tg;
- struct hdmi_v14_core_regs *core =
- &hdata->mode_conf.conf.v14_conf.core;
-
- hdata->mode_conf.cea_video_id =
- drm_match_cea_mode((struct drm_display_mode *)m);
- hdata->mode_conf.pixel_clock = m->clock * 1000;
- hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio;
+ struct hdmi_tg_regs *tg = &hdata->mode_conf.tg;
+ struct hdmi_v14_core_regs *core = &hdata->mode_conf.core;
hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
hdmi_set_reg(core->v_line, 2, m->vtotal);
/* preserve mode information for later use. */
drm_mode_copy(&hdata->current_mode, mode);
- if (hdata->type == HDMI_TYPE13)
- hdmi_v13_mode_set(hdata, mode);
- else
+ hdata->cea_video_id = drm_match_cea_mode(mode);
+
+ if (hdata->drv_data->type == HDMI_TYPE14)
hdmi_v14_mode_set(hdata, mode);
}
{
struct hdmi_context *hdata = display_to_hdmi(display);
- mutex_lock(&hdata->hdmi_mutex);
- if (!hdata->powered) {
- mutex_unlock(&hdata->hdmi_mutex);
+ if (!hdata->powered)
return;
- }
- mutex_unlock(&hdata->hdmi_mutex);
hdmi_conf_apply(hdata);
}
{
struct hdmi_resources *res = &hdata->res;
- mutex_lock(&hdata->hdmi_mutex);
- if (hdata->powered) {
- mutex_unlock(&hdata->hdmi_mutex);
+ if (hdata->powered)
return;
- }
hdata->powered = true;
- mutex_unlock(&hdata->hdmi_mutex);
-
pm_runtime_get_sync(hdata->dev);
if (regulator_bulk_enable(res->regul_count, res->regul_bulk))
{
struct hdmi_resources *res = &hdata->res;
- mutex_lock(&hdata->hdmi_mutex);
if (!hdata->powered)
- goto out;
- mutex_unlock(&hdata->hdmi_mutex);
+ return;
/* HDMI System Disable */
hdmi_reg_writemask(hdata, HDMI_CON_0, 0, HDMI_EN);
pm_runtime_put_sync(hdata->dev);
- mutex_lock(&hdata->hdmi_mutex);
hdata->powered = false;
-
-out:
- mutex_unlock(&hdata->hdmi_mutex);
}
static void hdmi_dpms(struct exynos_drm_display *display, int mode)
hdata = container_of(work, struct hdmi_context, hotplug_work.work);
- mutex_lock(&hdata->hdmi_mutex);
- hdata->hpd = gpio_get_value(hdata->hpd_gpio);
- mutex_unlock(&hdata->hdmi_mutex);
-
if (hdata->drm_dev)
drm_helper_hpd_irq_event(hdata->drm_dev);
}
return ret;
}
-static struct s5p_hdmi_platform_data *drm_hdmi_dt_parse_pdata
- (struct device *dev)
-{
- struct device_node *np = dev->of_node;
- struct s5p_hdmi_platform_data *pd;
- u32 value;
-
- pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
- if (!pd)
- goto err_data;
-
- if (!of_find_property(np, "hpd-gpio", &value)) {
- DRM_ERROR("no hpd gpio property found\n");
- goto err_data;
- }
-
- pd->hpd_gpio = of_get_named_gpio(np, "hpd-gpio", 0);
-
- return pd;
-
-err_data:
- return NULL;
-}
-
static struct of_device_id hdmi_match_types[] = {
{
.compatible = "samsung,exynos5-hdmi",
static int hdmi_probe(struct platform_device *pdev)
{
struct device_node *ddc_node, *phy_node;
- struct s5p_hdmi_platform_data *pdata;
- struct hdmi_driver_data *drv_data;
const struct of_device_id *match;
struct device *dev = &pdev->dev;
struct hdmi_context *hdata;
struct resource *res;
int ret;
- if (!dev->of_node)
- return -ENODEV;
-
- pdata = drm_hdmi_dt_parse_pdata(dev);
- if (!pdata)
- return -EINVAL;
-
hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
if (!hdata)
return -ENOMEM;
+ match = of_match_device(hdmi_match_types, dev);
+ if (!match)
+ return -ENODEV;
+
+ hdata->drv_data = match->data;
hdata->display.type = EXYNOS_DISPLAY_TYPE_HDMI;
hdata->display.ops = &hdmi_display_ops;
- mutex_init(&hdata->hdmi_mutex);
-
platform_set_drvdata(pdev, hdata);
- match = of_match_node(hdmi_match_types, dev->of_node);
- if (!match)
- return -ENODEV;
-
- drv_data = (struct hdmi_driver_data *)match->data;
- hdata->type = drv_data->type;
- hdata->phy_confs = drv_data->phy_confs;
- hdata->phy_conf_count = drv_data->phy_conf_count;
-
- hdata->hpd_gpio = pdata->hpd_gpio;
hdata->dev = dev;
+ hdata->hpd_gpio = of_get_named_gpio(dev->of_node, "hpd-gpio", 0);
+ if (hdata->hpd_gpio < 0) {
+ DRM_ERROR("cannot get hpd gpio property\n");
+ return hdata->hpd_gpio;
+ }
ret = hdmi_resources_init(hdata);
if (ret) {
}
out_get_phy_port:
- if (drv_data->is_apb_phy) {
+ if (hdata->drv_data->is_apb_phy) {
hdata->regs_hdmiphy = of_iomap(phy_node, 0);
if (!hdata->regs_hdmiphy) {
DRM_ERROR("failed to ioremap hdmi phy\n");
goto err_hdmiphy;
}
- hdata->hpd = gpio_get_value(hdata->hpd_gpio);
-
INIT_DELAYED_WORK(&hdata->hotplug_work, hdmi_hotplug_work_func);
ret = devm_request_threaded_irq(dev, hdata->irq, NULL,