2 * Copyright (C) 2013 Red Hat
3 * Author: Rob Clark <robdclark@gmail.com>
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 as published by
7 * the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * You should have received a copy of the GNU General Public License along with
15 * this program. If not, see <http://www.gnu.org/licenses/>.
21 struct drm_bridge base
;
25 unsigned long int pixclock
;
27 #define to_hdmi_bridge(x) container_of(x, struct hdmi_bridge, base)
29 static void hdmi_bridge_destroy(struct drm_bridge
*bridge
)
31 struct hdmi_bridge
*hdmi_bridge
= to_hdmi_bridge(bridge
);
32 hdmi_unreference(hdmi_bridge
->hdmi
);
33 drm_bridge_cleanup(bridge
);
37 static void hdmi_bridge_pre_enable(struct drm_bridge
*bridge
)
39 struct hdmi_bridge
*hdmi_bridge
= to_hdmi_bridge(bridge
);
40 struct hdmi
*hdmi
= hdmi_bridge
->hdmi
;
41 struct hdmi_phy
*phy
= hdmi
->phy
;
44 phy
->funcs
->powerup(phy
, hdmi_bridge
->pixclock
);
45 hdmi_set_mode(hdmi
, true);
48 static void hdmi_bridge_enable(struct drm_bridge
*bridge
)
52 static void hdmi_bridge_disable(struct drm_bridge
*bridge
)
56 static void hdmi_bridge_post_disable(struct drm_bridge
*bridge
)
58 struct hdmi_bridge
*hdmi_bridge
= to_hdmi_bridge(bridge
);
59 struct hdmi
*hdmi
= hdmi_bridge
->hdmi
;
60 struct hdmi_phy
*phy
= hdmi
->phy
;
63 hdmi_set_mode(hdmi
, false);
64 phy
->funcs
->powerdown(phy
);
67 static void hdmi_bridge_mode_set(struct drm_bridge
*bridge
,
68 struct drm_display_mode
*mode
,
69 struct drm_display_mode
*adjusted_mode
)
71 struct hdmi_bridge
*hdmi_bridge
= to_hdmi_bridge(bridge
);
72 struct hdmi
*hdmi
= hdmi_bridge
->hdmi
;
73 int hstart
, hend
, vstart
, vend
;
78 hdmi_bridge
->pixclock
= mode
->clock
* 1000;
80 hdmi
->hdmi_mode
= drm_match_cea_mode(mode
) > 1;
82 hstart
= mode
->htotal
- mode
->hsync_start
;
83 hend
= mode
->htotal
- mode
->hsync_start
+ mode
->hdisplay
;
85 vstart
= mode
->vtotal
- mode
->vsync_start
- 1;
86 vend
= mode
->vtotal
- mode
->vsync_start
+ mode
->vdisplay
- 1;
88 DBG("htotal=%d, vtotal=%d, hstart=%d, hend=%d, vstart=%d, vend=%d",
89 mode
->htotal
, mode
->vtotal
, hstart
, hend
, vstart
, vend
);
91 hdmi_write(hdmi
, REG_HDMI_TOTAL
,
92 HDMI_TOTAL_H_TOTAL(mode
->htotal
- 1) |
93 HDMI_TOTAL_V_TOTAL(mode
->vtotal
- 1));
95 hdmi_write(hdmi
, REG_HDMI_ACTIVE_HSYNC
,
96 HDMI_ACTIVE_HSYNC_START(hstart
) |
97 HDMI_ACTIVE_HSYNC_END(hend
));
98 hdmi_write(hdmi
, REG_HDMI_ACTIVE_VSYNC
,
99 HDMI_ACTIVE_VSYNC_START(vstart
) |
100 HDMI_ACTIVE_VSYNC_END(vend
));
102 if (mode
->flags
& DRM_MODE_FLAG_INTERLACE
) {
103 hdmi_write(hdmi
, REG_HDMI_VSYNC_TOTAL_F2
,
104 HDMI_VSYNC_TOTAL_F2_V_TOTAL(mode
->vtotal
));
105 hdmi_write(hdmi
, REG_HDMI_VSYNC_ACTIVE_F2
,
106 HDMI_VSYNC_ACTIVE_F2_START(vstart
+ 1) |
107 HDMI_VSYNC_ACTIVE_F2_END(vend
+ 1));
109 hdmi_write(hdmi
, REG_HDMI_VSYNC_TOTAL_F2
,
110 HDMI_VSYNC_TOTAL_F2_V_TOTAL(0));
111 hdmi_write(hdmi
, REG_HDMI_VSYNC_ACTIVE_F2
,
112 HDMI_VSYNC_ACTIVE_F2_START(0) |
113 HDMI_VSYNC_ACTIVE_F2_END(0));
117 if (mode
->flags
& DRM_MODE_FLAG_NHSYNC
)
118 frame_ctrl
|= HDMI_FRAME_CTRL_HSYNC_LOW
;
119 if (mode
->flags
& DRM_MODE_FLAG_NVSYNC
)
120 frame_ctrl
|= HDMI_FRAME_CTRL_VSYNC_LOW
;
121 if (mode
->flags
& DRM_MODE_FLAG_INTERLACE
)
122 frame_ctrl
|= HDMI_FRAME_CTRL_INTERLACED_EN
;
123 DBG("frame_ctrl=%08x", frame_ctrl
);
124 hdmi_write(hdmi
, REG_HDMI_FRAME_CTRL
, frame_ctrl
);
126 // TODO until we have audio, this might be safest:
128 hdmi_write(hdmi
, REG_HDMI_GC
, HDMI_GC_MUTE
);
131 static const struct drm_bridge_funcs hdmi_bridge_funcs
= {
132 .pre_enable
= hdmi_bridge_pre_enable
,
133 .enable
= hdmi_bridge_enable
,
134 .disable
= hdmi_bridge_disable
,
135 .post_disable
= hdmi_bridge_post_disable
,
136 .mode_set
= hdmi_bridge_mode_set
,
137 .destroy
= hdmi_bridge_destroy
,
141 /* initialize bridge */
142 struct drm_bridge
*hdmi_bridge_init(struct hdmi
*hdmi
)
144 struct drm_bridge
*bridge
= NULL
;
145 struct hdmi_bridge
*hdmi_bridge
;
148 hdmi_bridge
= kzalloc(sizeof(*hdmi_bridge
), GFP_KERNEL
);
154 hdmi_bridge
->hdmi
= hdmi_reference(hdmi
);
156 bridge
= &hdmi_bridge
->base
;
158 drm_bridge_init(hdmi
->dev
, bridge
, &hdmi_bridge_funcs
);
164 hdmi_bridge_destroy(bridge
);